Python 中的 super() 函数真的是调用父类吗?
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 函数没有任何意义了。