Python 多重继承的问题 为什么以下代码里 Base 的 __init__ 没有被调用

2020-07-17 21:30:32 +08:00
 doraemon1293
class Base():
    def __init__(self):
        print("Base")

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

class Second(Base):
    def __init__(self):
        print("second")

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

为何输出结果为

second

first

third

为什么 First 中 super().init() 没有被调用呢

如果代码改为

class Base():
    def __init__(self):
        print("Base")

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

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

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

则输出结果为

Base

second

first

third

1824 次点击
所在节点    Python
10 条回复
gwy15
2020-07-17 21:53:20 +08:00
调用 super() 的时候实际上会跟随 MRO 进行链式调用,在这个例子里面,调用链是(从左到右宽度优先搜索)
`Third` -> `First` -> `Second` -> `Base` -> `object`
可以用 `Third.mro()` 查看。

因此,在调用的时候,Third.__init__ 里面 super().__init__() 实际调用的是 Second.__init__(self),而 Second.__init__ 里面没有继续调用 super,所以 Base 的 __init__ 没有调用。
gwy15
2020-07-17 21:57:45 +08:00
上面有点笔误
Third -> First -> Second -/-> Base
>>> second
>>> first
>>> third
marquina
2020-07-17 22:01:29 +08:00
@gwy15 更准确地说,Third.__init__里的 super().__init__()调用的是 First.__init__,First.__init__里的 super().__init__调用的是 Second.__init__。
marquina
2020-07-17 22:02:55 +08:00
@gwy15 才看到你#2 的回复😂
doraemon1293
2020-07-17 22:03:25 +08:00
感谢回答
两种情况 打印 Third.__mro__ 结果都是
(<class '__main__.Third'>, <class '__main__.First'>, <class '__main__.Second'>, <class '__main__.Base'>, <class 'object'>)
多重继承 super 不是从左到右查找吗 为什么会调用 Second.__init__(self)

我把打印的代码改成标注开始和结束
```
class Base():
def __init__(self):
print("Base")

class First(Base):
def __init__(self):
print("first start")
super().__init__()
print("first end")
class Second(Base):
def __init__(self):
print("second start")
# super().__init__()
print("second end")

class Third(First,Second):
def __init__(self):
super().__init__()
print("third")
print(Third.__mro__)
Third()
```
结果如下
first start
second start
second end
first end
third
为什么 first 先被调用 然而 first 里的 super().__init__()没有任何效果呢?
doraemon1293
2020-07-17 22:04:57 +08:00
刚看到你的更正 请忽略我上面的回复
为什么 First.__init__里的 super().__init__调用的是 Second.__init__。
First 的 super 不应该调用他的父类 Base 吗?
gwy15
2020-07-17 22:07:34 +08:00
@doraemon1293 super 是根据 MRO 链走的,不是“父类”。
doraemon1293
2020-07-17 22:17:35 +08:00
@gwy15
明白了 一直以为 super 是调用父类 多谢解答
oahebky
2020-07-17 22:22:45 +08:00
这是个新式类+钻石继承的问题。

没有什么特别的东西,就是“规定”。

具体参见 《 learning Python 》(有中文版)类的高级主题部分 - 第 31 章。

自认为没有能力解释得比书上更好,所以不多做解释,仅指路。
gulu
2020-07-18 10:47:41 +08:00
不如亲自看看 Python 之父当时解决 MRO 的思路:
http://python-history.blogspot.com/2010/06/method-resolution-order.html?m=1

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/690995

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX