Python 为什么super()继承了;“错误”;上课?
我正在研究钻石问题,有一个问题:Python 为什么super()继承了;“错误”;上课?,python,super,diamond-problem,Python,Super,Diamond Problem,我正在研究钻石问题,有一个问题: A类: 定义初始化(自): 打印(“这是A类”) B(A)类: 定义初始化(自): 打印(“这是B类”) super()。\uuuu init\uuuuu() C(A)类: 定义初始化(自): 打印(“这是C类”) super()。\uuuu init\uuuuu() D类(B、C): 定义初始化(自): 打印(“这是D类”) super()。\uuuu init\uuuuu() i=D() 它按预期工作,这很好,但我想知道为什么super()。class
A类:
定义初始化(自):
打印(“这是A类”)
B(A)类:
定义初始化(自):
打印(“这是B类”)
super()。\uuuu init\uuuuu()
C(A)类:
定义初始化(自):
打印(“这是C类”)
super()。\uuuu init\uuuuu()
D类(B、C):
定义初始化(自):
打印(“这是D类”)
super()。\uuuu init\uuuuu()
i=D()
它按预期工作,这很好,但我想知道为什么super()。class B
中的\uu init\uuu()
没有转到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()行为背后的逻辑是什么
当在网上问这个问题时,几乎每个人都把我和这个联系在一起:但我真的不明白,他的解释似乎太技术化了,他的例子(我理解的为数不多的例子)比他们应该解释的要复杂得多……这就是为什么我想要一个……更简单的解释
- Super()必须遵循MRO,即使父类上的继承会提示其他情况
- Super()无法转到父类的父类,因此如果父类中有Super,它将转到第二个继承的类
- 另外,有点不相关,但在真实的工作环境中,钻石问题有多普遍?似乎是一种非常复杂的工作方式
A
/ \
B C
\ /
D
MRO从第一级(直接父类)、从左到右(B
然后C
)再到下一级、从左到右(此处仅为A
)寻求方法解析
在这种情况下,由于您从A
继承了B
和C
,顶层解析为单个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
的初始化两次,这不需要发生。在长继承链或复杂的初始化例程中,这是非常低效的。简单的回答是D
的mro是(D,B,C,A,object)
。这是因为B
和C
继承自A
,因此A
必须在后面。因为这是MRO的下一个实现。这就是为什么你服从于超级。2.因为你实际上叫它两次。同样,这也是为什么您要遵从super。“如果一个类有一个super(),并且它从父类继承,那么它应该去那里。”不,它不应该。那是你根本的误解。这只适用于非多重继承的简单情况。但一般来说,super
提供了一个代理对象,它将推迟到MRO中的下一个类。这就是为什么您必须在参与协作多重继承的所有类中使用super
(这就是为什么您的第二个示例中断的原因)。@OlivierMelançon no,这在这里是适用的。super()
只是名称不好。它可能应该像next\u class()
之类的调用。你不是第一个有这种困惑的人。
A
/ \
B C
\ /
D
class D(B, C):
def __init__(self):
print("This is class D")
B.__init__(self)
C.__init__(self)
A A
| |
B C
\ /
D