本文是介绍 Python 中继承或多继承时 super 的工作原理和方法解析顺序(Method Resolution Order, MRO), 从根本上理解super(cls, inst) 背后到底是什么意思和 MRO。在阅读相关代码时,一定要切记当前 self 是谁,类型是什么,继承关系是什么,MRO是什么, 这样才能准确把握代码的调用流程。
在 demo 之前,先说两个知识点:
-
MRO 方法解析顺序
对于你定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)列表,它代表了类继承的顺序,我们可以使用下面的方式获得某个类的 MRO 列表: MyClass.mro() 或 MyClass.__mro__或 obj.__class__.mro()那这个 MRO 列表的顺序是怎么定的呢,它是通过一个 C3 线性化算法来实现的,总的来说,一个类的 MRO 列表就是合并所有父类的 MRO 列表,并遵循以下三条原则:
a. 子类永远在父类前面
b. 如果有多个父类,会根据它们在列表中的顺序被检查
c. 如果对下一个类存在两个合法的选择,选择第一个父类 -
super 的工作原理
def super(cls, inst): mro = inst.__class__.mro() return mro[mor.index(cls) + 1]
其中,cls 代表类,inst 代表实例,上面的代码做了两件事:
a. 获取 inst 的 MRO 列表
b. 查找 cls 在当前 MRO 列表中的 index, 并返回它的下一个类,即 mro[index + 1]所以 super 其实和父类没有实质性的关联。即当你使用 super(cls, inst) 时,Python 会在 inst 的 MRO 列表上搜索 cls 的下一个类。
-
拓展:
根据 super 的工作原理,如果你在调用 super() 的地方,修改第一个参数,则调用路径就会发生改变,哈哈
示例代码:
类的继承关系如图:
Base
/ \
/ \
A B
\ /
\ /
MyClass
class Base(object):
def __init__(self):
print 'enter class base'
print 'In class Base: self = {0}'.format(self)
print 'leave class base'
class A(Base):
def __init__(self):
print 'enter class A'
print 'In class A: self = {0}'.format(self)
# 重点关注:super(A, self).__init__() 到底执行的是什么
print '---111---'
super(A, self).__init__()
print '---222---'
print 'leave class A'
class B(Base):
def __init__(self):
print 'enter class B'
print 'In class B: self = {0}'.format(self)
super(B, self).__init__()
print 'leave class B'
class MyClass(A, B):
def __init__(self):
print 'enter class MyClass'
print 'In class MyClass: self = {0}'.format(self)
print 'MRO = {0}'.format(MyClass.mro())
super(MyClass, self).__init__()
print 'leave class MyClass'
obj = MyClass()
The output is
enter class MyClass
In class MyClass: self = <__main__.MyClass object at 0x0000000002699080>
MRO = [<class '__main__.MyClass'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <type 'object'>]
enter class A
In class A: self = <__main__.MyClass object at 0x0000000002699080>
---111---
enter class B
In class B: self = <__main__.MyClass object at 0x0000000002699080>
enter class base
In class Base: self = <__main__.MyClass object at 0x0000000002699080>
leave class base
leave class B
---222---
leave class A
leave class MyClass
流程说明:
首先看类 MyClass 的 __init__ 方法:
super(MyClass, self).__init__()
这里的 self 是当前 MyClass 的实例,self.__class__.mro() 结果是:
[<class ‘__main__.MyClass’>, <class ‘__main__.A’>, <class ‘__main__.B’>, <class ‘__main__.Base’>, <type ‘object’>]
可以看到,MyClass 的下一个类是 A,于是,跳到了 A 的 __init__,这时会打印出 enter class A,并执行下面一行代码:
super(A, self).__init__()
注意,这里的 self 也是当前 MyClass 的实例,MRO 列表跟上面是一样的,搜索 A 在 MRO 中的下一个类,发现是 B,于是,跳到了 B 的 __init__,这时会打印出 enter classs B,而不是 enter class Base。
整个过程还是比较清晰的,关键是要理解 super 的工作方式,而不是想当然地认为 super 调用了父类的方法。
参考: https://www.cnblogs.com/silencestorm/p/8404046.html