python多继承使用super将构造函数传递给参数

问题描述 投票:31回答:2

考虑下面的python代码片段

class A(object):
    def __init__(self, a):
        self.a = a

class B(A):
    def __init__(self, a, b):
        super(B, self).__init__(a)
        self.b = b

class C(A):
    def __init__(self, a, c):
        super(C, self).__init__(a)
        self.c = c

class D(B, C):
    def __init__(self, a, b, c, d):
        #super(D,self).__init__(a, b, c) ???
        self.d = d

我想知道如何将abc传递给相应的基类构造函数。

谢谢,

python multiple-inheritance super diamond-problem
2个回答
46
投票

好吧,在处理一般的多重继承时,你的基类(不幸的是)应该设计为多重继承。你的例子中的类BC不是,因此你找不到在super中应用D的正确方法。

为多重继承设计基类的常用方法之一是让中级基类在他们不想使用的__init__方法中接受额外的args,并将它们传递给他们的super调用。

这是在python中执行此操作的一种方法:

class A(object):
    def __init__(self,a):
        self.a=a

class B(A):
    def __init__(self,b,**kw):
        self.b=b
        super(B,self).__init__(**kw)

 class C(A):
    def __init__(self,c,**kw):
        self.c=c
        super(C,self).__init__(**kw)

class D(B,C):
    def __init__(self,a,b,c,d):
        super(D,self).__init__(a=a,b=b,c=c)
        self.d=d

这可以被视为令人失望,但这就是它的方式。


9
投票

不幸的是,没有办法在不更改Base类的情况下使用super()来完成这项工作。对BC的构造函数的任何调用将试图调用Method Resolution Order中的下一个类,它将始终是BC而不是AB类构造函数所假设的C类。

另一种方法是显式调用构造函数,而不在每个类中使用super()

class A(object):
    def __init__(self, a):
        object.__init__()
        self.a = a

class B(A):
    def __init__(self, a, b):
        A.__init__(self, a)
        self.b = b

class C(object):
    def __init__(self, a, c):
        A.__init__(self, a)
        self.c = c

class D(B, C):
    def __init__(self, a, b, c, d):
        B.__init__(self, a, b)
        C.__init__(self, a, c)
        self.d = d 

这里仍有一个缺点,因为A构造函数将被调用两次,这在这个例子中并没有太大影响,但可能会导致更复杂的构造函数出现问题。您可以包含一个检查以防止构造函数多次运行。

class A(object):
    def __init__(self, a):
        if hasattr(self, 'a'):
            return
        # Normal constructor.

有人会称这是super()的缺点,从某种意义上来说,它也只是多重继承的一个缺点。钻石继承模式通常容易出错。而且它们的许多变通方法会导致更加混乱且容易出错的代码。有时,最好的答案是尝试重构代码以减少多重继承。

© www.soinside.com 2019 - 2024. All rights reserved.