为什么super()继承了“错误”的类?

2024-04-28 13:03:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在研究钻石问题,有一个问题:


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

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


Tags: 代码selfinitismaindef方式this
1条回答
网友
1楼 · 发布于 2024-04-28 13:03:54

您需要记住,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的初始化,这不需要发生。在长继承链或复杂的初始化例程中,这是非常低效的

相关问题 更多 >