Python 中的钻石继承

Sek*_*mer 5 python inheritance multiple-inheritance diamond-problem

关于python中菱形继承的问题:

  A
/   \
B    C
\   /
  D
Run Code Online (Sandbox Code Playgroud)

我首先创建了这个

class A:
    def __init__(self):
        print('a')

class B(A):
    def __init__(self):
        print('b')
        A.__init__(self)

class C(A):
    def __init__(self):
        print('c')
        A.__init__(self)

class D(B,C):
    def __init__(self):
        print('d')
        super().__init__()

test = D()
Run Code Online (Sandbox Code Playgroud)

它的输出是 d, b, a

改变B和C之后A.__init__() to super()

class A:
    def __init__(self):
        print('a')

class B(A):
    def __init__(self):
        print('b')
        super().__init__()  # THIS AND ^^

class C(A):
    def __init__(self):
        print('c')
        super().__init__()   # THIS  ^^

class D(B,C):
    def __init__(self):
        print('d')
        super().__init__()

test = D()
Run Code Online (Sandbox Code Playgroud)

输出为 d、b、c、a

有人可以解释为什么该程序会这样运行吗?

Avi*_*niv 6

为了理解super()我们必须了解 MRO 概念。

MRO 或方法解决顺序

当调用子方法时,应该有一些内部机制来确定调用哪个方法。

MRO 定义了搜索基类以执行方法的顺序。

正在查找方法:

  1. 在儿童班级本身。
  2. 按照继承中指定的顺序,在 DFS 中。

MRO 允许将继承图转换为线性列表以进行迭代。

代码中发生了什么

  1. 第一版

在此版本中,D定义了类:

class D(B,C):
    def __init__(self):
        print('d')
        super().__init__()
Run Code Online (Sandbox Code Playgroud)

因此,当D对象被创建时,我们看到“d”作为第一个输入。

然后在D构造函数中调用:

super().__init__()
Run Code Online (Sandbox Code Playgroud)

super()方法调用 MRO 中的下一个类。

D维护、维修和运营是:

# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
print(D.__mro__)
Run Code Online (Sandbox Code Playgroud)

B因此,下一个类的B构造函数已被调用,我们见证了B第二个输出。

B构造函数是:

class B(A):
    def __init__(self):
        print('b')
        A.__init__(self)
Run Code Online (Sandbox Code Playgroud)

因此它直接调用 A 类构造函数,我们看到“A”是第三个也是最后一个输出。

  1. 第二版

在此版本中,类D构造函数与以前相同,因此第一个输出再次为“d”。

然后,像之前一样B调用构造函数,并打印“b”作为第二个输出:

class B(A):
    def __init__(self):
        print('b')
        super().__init__()
Run Code Online (Sandbox Code Playgroud)

然而,这一次,super()又被召唤了。

在查看DMRO时(注意我们是构造函数D中的对象B,所以相关的MRO是 of D):

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
Run Code Online (Sandbox Code Playgroud)

下一个类是C,因此C正在调用构造函数,我们见证“c”作为第三个输出:

class C(A):
    def __init__(self):
        print('c')
        super().__init__()
Run Code Online (Sandbox Code Playgroud)

最后,super()再次调用该方法,并在 MRO 之后我们以 class 结束A

class A:
    def __init__(self):
        print('a')
Run Code Online (Sandbox Code Playgroud)

最后的输出是'a',我们就完成了。

更多关于

阅读super()文档中有关方法的更多信息。