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

2018-07-05  本文已影响0人  SuperDi

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 函数没有任何意义了。

上一篇下一篇

猜你喜欢

热点阅读