我正在研究钻石问题,有一个问题:
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
它按照预期的方式工作,这很好,但是我想知道为什么class B
中的super().__init__()
不去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不仅仅是简单的跟随领导者。它创建类似于图的结构,并解析相同的继承以避免重复。在第一个示例中,您创建了菱形继承
MRO从第一级(直接父类)、从左到右(
B
然后C
)、然后从左到右(这里只有A
)再到下一级,寻求方法的解析在本例中,由于
B
和C
都继承自A
,因此顶层解析为单个A
,并创建上面的菱形图让我们来看第二个示例:
通过这种方式实施,您可以通过MRO有效地完成任务。您已获得遗产钻石,并将其制成遗产橄榄叉,看起来如下:
因此,您需要两次调用
A
的初始化,这不需要发生。在长继承链或复杂的初始化例程中,这是非常低效的相关问题 更多 >
编程相关推荐