Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么super()继承了;“错误”;上课?_Python_Super_Diamond Problem - Fatal编程技术网

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,它将转到第二个继承的类

  • 另外,有点不相关,但在真实的工作环境中,钻石问题有多普遍?似乎是一种非常复杂的工作方式


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

   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