Flo*_*nne 2 python super diamond-problem
我正在查看钻石问题并得到一个问题:
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()
Run Code Online (Sandbox Code Playgroud)
This is class D
This is class B
This is class C
This is class A
Run Code Online (Sandbox Code Playgroud)
它按预期工作,这很好,但我想知道为什么super().__init__()inclass 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'>)
Run Code Online (Sandbox Code Playgroud)
但我不知道为什么。
比这段代码的非 super() 实现具有相同的 MRO 但 A 打印两次非常奇怪:
This is class D
This is class B
This is class C
This is class A
Run Code Online (Sandbox Code Playgroud)
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
Run Code Online (Sandbox Code Playgroud)
这是相反的,我知道 MRO 是正确的,但奇怪的是实际执行并没有那样:
This is class D
This is class B
This is class A
This is class C
This is class A
Run Code Online (Sandbox Code Playgroud)
我想知道 super() 行为背后的逻辑是什么。
当在网上问这个问题时,几乎每个人都将我链接到这个:https : //rhettinger.wordpress.com/2011/05/26/super-thinked-super/但我真的不明白,他的解释似乎太技术和他的例子(我理解的少数几个)比解释这一点要复杂得多......这就是为什么我想要一个......更简单的解释。
Super() 必须遵循 MRO,即使父类上的继承不建议这样做?
Super() 无法转到父类的父类,因此如果父类中有 super 它将转到第二个继承的类?
此外,在真实的工作场所环境中看到钻石问题有多少不相关但有多普遍?似乎是一种非常复杂的工作方式。
您需要记住,MRO 不仅仅是简单的跟随领导者。它创建了一个类似图的结构并解析相同的继承以避免重复。在您的第一个示例中,您创建了一个菱形继承。
A
/ \
B C
\ /
D
Run Code Online (Sandbox Code Playgroud)
MRO 寻求从第一级(直接父类)、从左到右(Bthen C)、然后再上一级、从左到右(就A在此处)等方法的解析。
在这种情况下,因为您拥有B和C继承自A,顶级解析为单个A并创建上面的菱形图。
让我们看看你的第二个例子:
class D(B, C):
def __init__(self):
print("This is class D")
B.__init__(self)
C.__init__(self)
Run Code Online (Sandbox Code Playgroud)
通过以这种方式实施它,您可以有效地绕过 MRO。您已将继承钻石制成一个继承橄榄叉,如下所示:
A A
| |
B C
\ /
D
Run Code Online (Sandbox Code Playgroud)
因此,您调用了A两次初始化,这不需要发生。在长继承链或复杂的初始化例程中,这是非常低效的。
| 归档时间: |
|
| 查看次数: |
80 次 |
| 最近记录: |