为什么在多次继承中执行Base .__ init __(self)而不是super().__ init __()时会跳过__init__?

时间:2018-10-07 06:00:22

标签: python python-3.x multiple-inheritance super diamond-problem

为什么恰好

A.__init__()
B.__init__()
D.__init__()

按以下代码打印?特别是:

  1. 为什么C.__init__() 打印?

  2. 为什么我放C.__init__()而不是super().__init__()时打印A.__init__(self)

#!/usr/bin/env python3

class A(object):
    def __init__(self):
        super(A, self).__init__()
        print("A.__init__()")
class B(A):
    def __init__(self):
        A.__init__(self)
        print("B.__init__()")
class C(A):
    def __init__(self):
        A.__init__(self)
        print("C.__init__()")
class D(B, C):
    def __init__(self):
        super(D, self).__init__()
        print("D.__init__()")

D()

1 个答案:

答案 0 :(得分:6)

tl; dr:因为应该通过B.__init__调用C.__init__来调用super(B, self).__init__(),所以您绕过了该调用。


为什么不打印C .__ init __()?

因为您没有告诉。多重继承涉及合作,您已经使用了显式的类引用来拒绝这种合作。

如果您用super().__init__()替换了所有“超级类”调用(因为您已将其标记为Python 3),您将看到如下输出:

A.__init__()
C.__init__()
B.__init__()
D.__init__()

实际上,如果仅将B的“超级类”调用更改为以下任何一个,就会看到此输出:

super(B, self).__init__()
super().__init__()

那么在您的情况下A为什么不给C打电话?

在网站上有关MRO的其他地方复制概述良好的答案将是多余的。

如果我放置super().__ init __()而不是A .__ init __(self),为什么会打印C .__ init __()?

由于the no-argument super() goes left to right,因此首先查看B,然后在B内部使用显式类引用(A.__init__(self))。这样一来,您将失去D 作为超类C拥有的所有(大多数*)上下文。

super()是可以帮助您导航MRO的工具,如果您允许它,它会让您进入C.__init__()。但是在B中,您只是在调用A的类方法。

*您已经注意到C.__init__()从未被调用。但是,C仍显示在D.__bases__中:

(<class '__main__.B'>, <class '__main__.C'>)

D.__mro__中:

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

isinstance(D(), C) is True

简而言之,Python 知道 CD的超类,但是您给了C.__init__并以{{1} }实施。