美文网首页
Python 中的 super() 函数真的是调用父类吗?

Python 中的 super() 函数真的是调用父类吗?

作者: SuperDi | 来源:发表于2018-07-05 10:44 被阅读0次

    super() 这个函数我们一点都不陌生,比如 B 类继承 A 类,我们可以在 B 类中通过 super() 调用父类 A 中的方法,实际运行效果确实证明 super() 调用的父类方法,但是一旦我们将这个继承变成多重继承和多继承会发生什么呢?姑且举个栗子

    class A:
        def __init__(self):
            print("A")
    
    class B(A):
        def __init__(self):
            print("B")
            super().__init__()
    
    class C(A):
        def __init__(self):
            print("C")
            super().__init__()
    
    class D(B, C):
        def __init__(self):
            print("D")
            super().__init__()
    
    
    if __name__ == '__main__':
        d = D()
    

    以上的打印结果会是什么呢?如下

    E:\python3.exe E:/python_demo/test4.py
    D
    B
    C
    A
    Process finished with exit code 0
    

    按照我们以上的猜测,super() 调用的是父类方法,打印出 D 后按继承的顺序接着调用 B 中的 __init__() 函数,打印 B,B 又继承了 A ,那么此时应该调用 A 中的 __init__() 函数,接着调用 C 中的 __init__() 函数,输出结果应该是 D > B > A > C;
    而代码执行过程确是调用 B 之后接着调用 C 中的 __init__() 函数,然后再调用 A 中的 __init__() 函数,那么造成这种结果的原因是什么的?我们不妨在main函数再加一句打印语句

    if __name__ == '__main__':
        d = D()
        print(D.mro())
    

    执行结果如下

    E:\python3.exe E:/python_demo/test4.py
    D
    B
    C
    A
    [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
    

    可以看出执行 mro() 函数的结果和 super() 调用的顺序是一致的,mro() 函数执行最终会调用魔法函数 __mro__()

    总结

    super() 函数的调用顺序不是单纯的调用父类,而是根据 mro() 函数指定的调用顺序进行调用的,那么mro() 获取指定的调用顺序又是怎么实现的呢?答案是根据 python 内置的 C3 算法实现的

    小疑问

    或许到这应该有个疑问,这样调用的意义何在?

    还是以上面的例子为例说明一下,上面的继承关系如下:

         A (get())
       /   \
      B     C (重写 get())
       \   /
         D  调用 get() 函数
    

    比如父类 A 有一个 get 函数,我在 C 中重写了这个函数,那么我在 D 中调用的话当然是想要调用 C 中重写的 get 函数,但是如果按照之前对 super() 的认识,super() 调用父类,执行顺序应该是 D > B > A > C,此时调用的 get 函数就是调用的 父类 A 中的 get 函数了,此时 C 中重写的 get 函数没有任何意义了。

    相关文章

      网友评论

          本文标题:Python 中的 super() 函数真的是调用父类吗?

          本文链接:https://www.haomeiwen.com/subject/ghvuuftx.html