Python类的多继承以及super()机制
Python支持类的多继承,通过super()方法实现对不同父类的访问。
MRO
MRO 即 Method Resolution Order(方法解析顺序)。在调用方法时,会对当前类及其所有基类进行搜索,找到需要调用的方法,而 MRO 规定了这一搜索顺序。
例如,定义以下类继承结构:
1 | class Origin: |
可以通过方法 mro()
查看类 Current 的 MRO:
1 | print(Current.mro()) |
可以发现,MRO 列表第一个元素即当前类,最后一个元素是 object 类,同时满足:
- MRO 中类顺序保持定义时父类顺序
- 所有子类在父类之前
这里 MRO 列表中 BaseA 类位于 B 类之前,可以推测 MRO 默认是深度优先的。
之后的 super() 方法的父类查找机制也是建立在 MRO 顺序之上的。
super()
先给出结论:super() 方法用于访问参数对象所属类的 MRO 中,位于参数类之后的类。
这里有两个需要解释的点:
如果是多继承,super() 访问的是一个还是多个类?
提到了参数,但哪里有参数?
首先,super() 仅访问一个类,但不一定是父类,也可能是兄弟类,取决于嵌套调用时最初对象所属类的 MRO。那么最初对象又是什么?🤔 这里就到了要解释的第二个点。
先对前面定义的类做一些修改,具体看一下 super() 访问的机制。给每个类添加一个方法,打印并调用 super() 类中的方法(由于 Origin 的父类时 object 类,没有调用方法):
1 | class Origin: |
执行
1 | testObj = Current() |
这里并没有直接输出访问的类,但是可以看到每次调用都提供给
super()
方法两个参数。程序首先通过对象 testObj 调用
test()
方法,即 Current 类定义的 test()
方法。根据第一行输出,super()
方法中传入的是 Current
类,以及 Current 对象作为参数。之后嵌套调用 super()
类中的
test()
方法,根据第二行输出,可见访问了 A 类,在这里
super()
方法传入的是 A 类,以及 Current
对象作为参数。之后继续嵌套,又访问了 BaseA,B,以及 Origin
类。😶(其实通过 Origin 类中的 super()
最后访问到了 object
类,但并没有在 object 类中输出)
可以发现:向 super() 传递的第一个参数即调用 super() 方法所在的类,而第二个参数保持不变,是嵌套调用最开始的对象。而访问类的顺序和最初的类,即嵌套调用最开始对象所属类的 MRO 一致。
在 python2 版本,super() 方法的参数还不可省略:
1 | super(cls, obj) |
- cls: 当前类
- obj: 嵌套调用时的最初对象
实际上,super() 方法的访问逻辑如下:
1 | def super(cls, obj): |
即:访问 obj 所属类的 MRO 列表中,cls 的下一个类。
实用
super() 访问机制已经解释清楚了,但是这样的机制有什么好处呢?在实际应用中,super() 一般被用在初始化方法 __init__() 中,而这种嵌套调用对参数的要求必然十分严格,如何处理这种情况?
continue...