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

Lin*_*Lin 41 python multiple-inheritance super diamond-problem

考虑下面的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
Run Code Online (Sandbox Code Playgroud)

我想知道如何传递a,b以及c相应的基类的构造函数.

谢谢,

shx*_*hx2 50

好吧,在处理一般的多重继承时,你的基类(不幸的是)应该设计为多重继承.类BC在你的例子都没有,这样的话你找不到适用有道superD.

为多重继承设计基类的常用方法之一是,中级基类在其__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
Run Code Online (Sandbox Code Playgroud)

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


Bre*_*bel 12

不幸的是,如果super()不更改Base类,就无法使用它.该构造的任何呼吁BC打算尝试,并呼吁在隔壁班的方法解析顺序,这将永远是BC代替A类的BC类的构造函数承担.

另一种方法是在不使用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 
Run Code Online (Sandbox Code Playgroud)

还有这里的缺点的A构造函数被调用两次,它并没有真正有太多在这个例子中的效果,反而会造成更复杂的构造函数的问题.您可以包含一个检查以防止构造函数多次运行.

class A(object):
    def __init__(self, a):
        if hasattr(self, 'a'):
            return
        # Normal constructor.
Run Code Online (Sandbox Code Playgroud)

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


nad*_*pez 9

一个关键的概念:super不是指父类。它指的是 mro 列表中的下一个类,这取决于正在实例化的实际类。

因此,在调用时super().__init__,实际调用的方法是根据调用框架确定的。

这就是为什么这些类必须专门为 mixin 设计。

即使是仅继承自 , 的类也object应该调用super().__init__. 当然,当object__init__(**kwargs) 被调用时,kwargs此时应该为空;否则会引发错误。

例子:

class AMix:
    def __init__(self, a, **kwargs):
        super().__init__(**kwargs)
        self.a = a

          
class BMix:
    def __init__(self, b, **kwargs):
        super().__init__(**kwargs)
        self.b = b
    
          
class AB(AMix, BMix):
    def __init__(self, a, b):
        super().__init__(a=a, b=b)
      
      
ab = AB('a1', 'b2')

print(ab.a, ab.b)  #  -> a1 b2
Run Code Online (Sandbox Code Playgroud)