Python超多重继承问题



我是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(以及输出(将自动更新,而无需更改任何进一步的代码。