gpt4 book ai didi

python - 为什么super()继承 "wrong"类?

转载 作者:行者123 更新时间:2023-12-02 03:01:02 25 4
gpt4 key购买 nike

我正在研究菱形继承(钻石问题)并提出一个问题:


class A:
def __init__(self):
print("This is class A")

class B(A):
def __init__(self):
print("This is class B")
super().__init__()

class C(A):
def __init__(self):
print("This is class C")
super().__init__()

class D(B, C):
def __init__(self):
print("This is class D")
super().__init__()


i = D()

This is class D
This is class B
This is class C
This is class A

它按预期工作,这很好,但我想知道为什么 super().__init__()class B不会转到 class A而是调用 C。

如果一个类有 super() 并且它继承自父类,那么它应该去那里。

如果我在 B 上删除它,代码将不会到达 C 或 A。

我了解 MRO 以及它实际上如何按预期进行:

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

但我不知道为什么。

这很奇怪,这段代码的非 super() 实现具有相同的 MRO,但 A 打印了两次:


class A:
def __init__(self):
print("This is class A")

class B(A):
def __init__(self):
print("This is class B")
A.__init__(self)

class C(A):
def __init__(self):
print("This is class C")
A.__init__(self)

class D(B, C):
def __init__(self):
print("This is class D")
B.__init__(self)
C.__init__(self)


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

情况恰恰相反,我知道 MRO 是正确的,但奇怪的是实际执行却并非如此:

This is class D
This is class B
This is class A
This is class C
This is class A

我想知道 super() 行为背后的逻辑是什么。

当在网上询问这个问题时,几乎每个人都将我链接到此:https://rhettinger.wordpress.com/2011/05/26/super-considered-super/但我真的不明白,他的解释似乎太技术性了,他的例子(我理解的几个例子)比解释这一点要复杂得多……这就是为什么我想要一个……更简单的解释。

  • 即使父类的继承另有建议,Super() 也必须遵循 MRO?

  • Super() 无法转到父类的父类,因此如果父类中有 super,它将转到第二个继承类?

  • 此外,有点不相关,但在真实的工作环境中看到菱形继承(钻石问题)有多常见?看起来是一种非常复杂的工作方式。

最佳答案

您需要记住,MRO 不仅仅是简单的追随领导者。它创建类似图形的结构并解析相同的继承以避免重复。在第一个示例中,您创建了菱形继承(钻石问题)。

   A
/ \
B C
\ /
D

MRO 从第一级(直接父类)开始寻求方法解析,从左到右(B 然后 C),然后是下一个级别,从左到右(这里只是 A),依此类推。

在本例中,由于 BC 均继承自 A,因此顶层解析为单个 A 并创建上面的菱形图。

让我们看一下第二个示例:

class D(B, C):
def __init__(self):
print("This is class D")
B.__init__(self)
C.__init__(self)

通过这种方式实现,您可以有效地绕过 MRO。您已将继承钻石制成继承橄榄叉,如下所示:

 A   A
| |
B C
\ /
D

因此,您将调用 A 的初始化两次,这是不需要发生的。在长继承链或复杂的初始化例程中,这是非常低效的。

关于python - 为什么super()继承 "wrong"类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59975088/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com