【问题标题】:Why is an __init__ skipped when doing Base.__init__(self) in multiple inheritance instead of super().__init__()?为什么在多重继承中执行 Base.__init__(self) 而不是 super().__init__() 时会跳过 __init__?
【发布时间】:2018-10-07 06:00:22
【问题描述】:

为什么正是

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

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

  1. 为什么C.__init__()没有打印出来?

  2. 如果我输入super().__init__() 而不是A.__init__(self),为什么会打印C.__init__()

#!/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()

【问题讨论】:

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


    【解决方案1】:

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


    为什么没有打印 C.__init__()?

    因为你没有告诉它。多重继承涉及合作,您使用了显式的类引用,否认合作。

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

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

    事实上,如果您将B 的“super-like”调用更改为任一:

    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 also 作为超类 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__ 并最终运行您的 B.__init__ 实现。

    【讨论】:

    • 阅读您的回答后,我无法理解这一点。当其他类保留相同的?您只是在告诉我“它涉及合作”,我可以通过致电super 来解决它。这在问题中很明显。问题是这在内部实际上意味着什么,我如何理解它?例如,这是否意味着super 在调用之间维护状态?它处于什么状态,为什么?这怎么搞砸了?
    • super 不维护状态,但可用于轻松查找 MRO 上的下一个类。您不需要需要super(),您可以通过在B 中调用C.__init__ 来完成“super() 会做的事情”。如果您认为这看起来很奇怪,那么不相关的类应该以我同意的方式相互引用,这就是 super() 存在的原因。
    • super() 需要两件事,(a) 当前类和 (b) self 实例——它使用 (b) 的 MRO 和 (a) 的位置在 MRO 中找到下一个班级。在 Python3 中,这些东西不需要显式提供。
    • 回复:第一个超类中缺少 super 如何以及为什么会影响第二个超类中是否调用函数? 因为 让你从 B 到 C 的东西(至少在你的 D 实例的情况下)是 super() .
    • 天哪,B.__init__ 正在打电话给C.__init__?!?哇。谢谢,现在说得通了!!
    猜你喜欢
    • 2020-07-05
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    • 2021-11-28
    • 1970-01-01
    • 2016-11-29
    • 1970-01-01
    相关资源
    最近更新 更多