V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
doraemon1293
V2EX  ›  Python

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

  •  
  •   doraemon1293 · 2020-07-17 21:30:32 +08:00 · 1781 次点击
    这是一个创建于 1377 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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

    10 条回复    2020-07-18 10:47:41 +08:00
    gwy15
        1
    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
        2
    gwy15  
       2020-07-17 21:57:45 +08:00
    上面有点笔误
    Third -> First -> Second -/-> Base
    >>> second
    >>> first
    >>> third
    marquina
        3
    marquina  
       2020-07-17 22:01:29 +08:00
    @gwy15 更准确地说,Third.__init__里的 super().__init__()调用的是 First.__init__,First.__init__里的 super().__init__调用的是 Second.__init__。
    marquina
        4
    marquina  
       2020-07-17 22:02:55 +08:00
    @gwy15 才看到你#2 的回复😂
    doraemon1293
        5
    doraemon1293  
    OP
       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
        6
    doraemon1293  
    OP
       2020-07-17 22:04:57 +08:00
    刚看到你的更正 请忽略我上面的回复
    为什么 First.__init__里的 super().__init__调用的是 Second.__init__。
    First 的 super 不应该调用他的父类 Base 吗?
    gwy15
        7
    gwy15  
       2020-07-17 22:07:34 +08:00
    @doraemon1293 super 是根据 MRO 链走的,不是“父类”。
    doraemon1293
        8
    doraemon1293  
    OP
       2020-07-17 22:17:35 +08:00
    @gwy15
    明白了 一直以为 super 是调用父类 多谢解答
    oahebky
        9
    oahebky  
       2020-07-17 22:22:45 +08:00 via Android
    这是个新式类+钻石继承的问题。

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

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

    自认为没有能力解释得比书上更好,所以不多做解释,仅指路。
    gulu
        10
    gulu  
       2020-07-18 10:47:41 +08:00 via Android   ❤️ 1
    不如亲自看看 Python 之父当时解决 MRO 的思路:
    http://python-history.blogspot.com/2010/06/method-resolution-order.html?m=1
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3741 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 04:22 · PVG 12:22 · LAX 21:22 · JFK 00:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.