关于Python超级多重继承的问题

Question on Python super multiple inheritance

我是新手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'>)

其中 Class D 的 __init__ 被调用。但是,如果我将 class 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'>)

那么classD的__init__不会被调用,而是classC的,虽然class没有使用super函数

有人知道吗: 1、在第一段代码中,为什么__init__ of class D也被调用了? 2、第二段代码为什么调用了class C的__init__而没有调用class D的__init__

未能始终如一地使用 super 意味着您不能保证 MRO 将被正确执行。

在您的第一个示例中,在 E.__init__ 中对 B.__init__ 的显式调用可确保永远不会调用 C.__init__,因为 BC 之后MRO.

在第二个示例中,B 恰好是 E 之后的下一个 class,因此(还)没有任何问题。但随后在 C.__init__ 中,您再次使用 A.__init__(self) 而不是 super(C, self).__init__(),这意味着您直接从 C 跳到 A,绕过了 D应该是下一个。

在设计使用 super 的 class 层次结构 时(不仅仅是单个 class),您必须确保 every class使用super来保证selfruntime类型选择的MRO被遵循,而是而不是在编译时对父class方法进行硬编码调用。

正确的定义是

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')

在 Python 3 中,一些编译器魔法在调用 super 时提供了 "default" 参数。例如,在 E.__init__ 中,super().__init___() 等同于 super(C, self).__init__().

因为 self 的值(以及它的类型)在整个调用链中是不变的,所以每次使用 super() 都指向 MRO 中的下一个 class type(self)。在上面的示例中,这将产生输出

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 的定义中更改基 classes 的顺序,MRO(以及输出)将自动更新,而无需更改任何进一步的代码。