我是Python的新手,对超级函数和多重继承真的很困惑。
这是玩具代码:
class A():
def __init__(self):
print('Call class A')
print('Leave class A')
class C(A):
def __init__(self):
print('Call class C')
A.__init__(self)
print('Leave class C')
class D(A):
def __init__(self):
print('Call class D')
#A.__init__(self)
super(D,self).__init__()
print('Leave class D')
class B(A):
def __init__(self):
print('Call class B')
super(B,self).__init__()
print('Leave class B')
class E(C,B,D):
def __init__(self):
print('Call class E')
B.__init__(self)
#C.__init__(self)
#D.__init__(self)
print('Leave class E')
则输出为:
Call class E
Call class B
Call class D
Call class A
Leave class A
Leave class D
Leave class B
Leave class E
(<class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
其中调用类别D的CCD_ 1。但是,如果我将E类更改为:
class E(B,C,D):
def __init__(self):
print('Call class E')
B.__init__(self)
#C.__init__(self)
#D.__init__(self)
print('Leave class E')
其中B、C、D的顺序发生变化,则输出为:
Call class E
Call class B
Call class C
Call class A
Leave class A
Leave class C
Leave class B
Leave class E
(<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
则不会调用类D的__init__
,而是调用类C,尽管类不使用super
函数。
有人知道吗:1.在第一个代码中,为什么也调用D类的__init__
?2.在第二个代码中,为什么调用了类C的__init__
而不调用类D的__init__
?
如果不能始终如一地使用super
,则意味着您不能保证MRO能够正常运行。
在第一个示例中,E.__init__
中对B.__init__
的显式调用确保__init__
0永远不会被调用,因为B
在MRO中位于C
之后。
在第二个例子中,B
恰好是E
之后的下一个类,所以(还(没有任何中断。但在C.__init__
中,您再次使用A.__init__(self)
而不是super(C, self).__init__()
,这意味着您直接从C
跳到A
,绕过了本应位于下一个的D
。
当设计使用super
(而不仅仅是一个类(的类层次结构时,必须确保每个类都使用super
,以确保遵循运行时类型的self
选择的MRO,而不是在编译的时候对父类方法进行硬编码调用。
正确的定义是
class A:
def __init__(self):
print('Call class A')
super().__init__()
print('Leave class A')
class C(A):
def __init__(self):
print('Call class C')
super().__init__()
print('Leave class C')
class D(A):
def __init__(self):
print('Call class D')
super().__init__()
print('Leave class D')
class B(A):
def __init__(self):
print('Call class B')
super().__init__()
print('Leave class B')
class E(C,B,D):
def __init__(self):
print('Call class E')
super().__init__(self)
print('Leave class E')
在Python3中,当调用super
时,一些编译器魔术提供了"默认"参数。例如,在E.__init__
中,super().__init___()
等效于super(C, self).__init__()
。
因为self
的值(以及它的类型(在整个调用链中是恒定的,所以每次使用super()
都会引用type(self)
的MRO中的下一个类。在上面的例子中,这将因此产生输出
Call class E
Call class C
Call class B
Call class D
Call class A
Leave class A
Leave class D
Leave class B
Leave class C
Leave class E
如果在E
的定义中更改基类的顺序,MRO(以及输出(将自动更新,而无需更改任何进一步的代码。