请考虑以下情况:
class A(object):
def __init__(self):
print('Running A.__init__')
super(A,self).__init__()
class B(A):
def __init__(self):
print('Running B.__init__')
# super(B,self).__init__()
A.__init__(self)
class C(A):
def __init__(self):
print('Running C.__init__')
super(C,self).__init__()
class D(B,C):
def __init__(self):
print('Running D.__init__')
super(D,self).__init__()
foo=D()
因此,这些类形成了一个所谓的继承钻石:
A
/ \
B C
\ /
D
运行代码会产生
Running D.__init__
Running B.__init__
Running A.__init__
不好,因为跳过了C
s __init__
。其原因是因为B
的__init__
调用A
的__init__
直接。
。如果您取消评论
# super(B,self).__init__()
和注释掉
A.__init__(self)
该代码产生了更令人满意的结果:
Running D.__init__
Running B.__init__
Running C.__init__
Running A.__init__
现在,所有__init__
方法都被调用。请注意,在当时你定义B.__init__
你可能会 认为 这super(B,self).__init__()
是与调用A.__init__(self)
,但是你错了。在上述情况下,super(B,self).__init__()
实际上调用C.__init__(self)
。
圣烟,B
一无所知C
,却super(B,self)
知道调用C
的__init__
?原因是因为self.__class__.mro()
包含C
。换句话说,self
(或以上所述foo
)了解C
。
所以要小心-两者不可互换。它们可以产生截然不同的结果。
使用super
有陷阱。继承图中的所有类之间需要相当大的协调。(例如,它们必须具有相同的呼叫签名__init__
,因为任何特定的__init__
人都不知道__init__
super
接下来会呼叫另一个,或者使用**kwargs
。)此外,您必须在super
任何地方都保持一致。跳过一次(如上例所示),您将失去的全部目的super
。请参阅链接以了解更多陷阱。
如果您完全控制类的层次结构,或者避免使用继承菱形,则不需要super
。