在多级和多级继承中使用 super()

Posted

技术标签:

【中文标题】在多级和多级继承中使用 super()【英文标题】:Usage of super() in Multiple and Multilevel inheritance 【发布时间】:2020-07-04 16:15:18 【问题描述】:

我是多级和多级继承的新手。我试图执行一个例子:

class First(object):
    def __init__(self):
        super().__init__()
        print("first")

class Second(object):
    def __init__(self):
        super().__init__()
        print("second")

class Third(First, Second):
    def __init__(self):
        super().__init__()
        print("third")
Third()

我得到的输出是:

second
first
third
<__main__.Third at 0x21bbaf2fc88>

谁能解释一下这个输出的原因? 我期望输出是:

first
second
third

因为第三类的 __init__() 会调用第一类的 __init__()(因为它在父列表中是第一个),它会首先打印第二类的 __init__(),最后是第三类的 __init__()。

MRO 打印出我预期的结果。

print(Third.__mro__)

打印

(__main__.Third, __main__.First, __main__.Second, object)

【问题讨论】:

【参考方案1】:

如果你调用super().__init__()之前你调用print(xxx),显示的顺序是正确的。

如果您希望订单显示在“例外”选项卡中,您可以将每个print(xxx) 替换为super().__init__(),这样就可以解决问题。

代码:

class First(object):
    def __init__(self):
        print("first")
        super().__init__()

class Second(object):
    def __init__(self):
        print("second")
        super().__init__()

class Third(First, Second):
    def __init__(self):
        print("third")            
        super().__init__()
Third()

【讨论】:

如果我在 super 之后有打印,你如何证明订单的合理性。在第一类和第二类的情况下,super().__init__() 没有做任何事情 第一个答案:这与在递归中调整打印顺序相同。第二个答案:super() 并不意味着你的父类,它意味着 MRO 列表中的下一个,这就是为什么 First 中的 super() 调用 Second.__init__ 而不是 object.__init__【参考方案2】:

这似乎只是您在__init__ 中打印时的产物。您当前的代码在调用super().__init__ 之后打印,因此继承层次结构以相反的顺序打印出来。如果您在超级调用之前打印,它将与 MRO 的顺序相同。如果你用两种方式打印,也许最容易理解:

class First(object):
    def __init__(self):
        print("first (top)")
        super().__init__()
        print("first (bottom)")

class Second(object):
    def __init__(self):
        print("second (top)")
        super().__init__()
        print("second (bottom)")

class Third(First, Second):
    def __init__(self):
        print("third (top)")
        super().__init__()
        print("third (bottom)")

现在Third() 的输出应该是:

third (top)
first (top)
second (top)
second (bottom)
first (bottom)
third (bottom)

您看到的输出&lt;__main__.Third ...&gt; 不是由您的任何代码打印的,而是由交互式shell 打印的。这是调用类的实例Third结果。如果您执行instance = Third(),您将看不到这一点,因为该值将存储到变量中,而不是打印出来。 REPL(Read Eval Print Loop)仅在 Python 以交互方式运行时运行,它不会在您导入或作为脚本运行的模块中进行任何额外的打印。

【讨论】:

不应该先(下)在第一个(上)之后打印。神器是什么意思? 不,所有的调用都是嵌套的。 Third.__init__ 调用First.__init__,它调用Second.__init__(它调用object.__init__,它什么都不做)。 super() 表示“MRO 的下一个”,而不是“我所有的父类”。这就是为什么你会得到First->Second 调用,而不是First 调用object 的原因,就像它对不同实例所做的那样。 Third.__init__ 调用 First.__init__ 调用 object.__init__ 什么都不做。 First.__init__ 不像你提到的那样调用 Second.__init__ 不,我猜对了。这就是为什么您按照我显示的顺序获得打印输出的原因(我通过运行代码对其进行了测试,这不仅仅是理论)。 Python 的super 真的是超级。它在多重继承的情况下做了一些特殊的事情,这样两个互不了解的基类仍然可以协作。在这种情况下,它是First.__init__ 调用super().__init__(),对于Third 实例,这意味着接下来调用Second.__init__。这很奇怪,但很有用!如果您直接创建了First 实例,它不会那样做,正如您所说,它会直接跳转到object.__init__

以上是关于在多级和多级继承中使用 super()的主要内容,如果未能解决你的问题,请参考以下文章

如何使用类实现多级继承

Lombok @Builder 用于具有强制字段的多级继承中的类

如何首先在代码中实现多级继承

实体框架+多级继承+EF代码优先

如何为多级组合类设计继承

多级继承 C++