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
好吧,在处理一般的多重继承时,你的基类(不幸的是)应该设计为多重继承.类B和C在你的例子都没有,这样的话你找不到适用有道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
Run Code Online (Sandbox Code Playgroud)
这可以被视为令人失望,但这就是它的方式.
Bre*_*bel 12
不幸的是,如果super()不更改Base类,就无法使用它.该构造的任何呼吁B或C打算尝试,并呼吁在隔壁班的方法解析顺序,这将永远是B或C代替A类的B和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
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(),而且在某种意义上说,但它也只是一般多重继承的一个缺点.钻石继承模式通常容易出错.而且它们的许多变通方法会导致更加混乱且容易出错的代码.有时,最好的答案是尝试重构代码以减少多重继承.
一个关键的概念: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)