Python多继承中属性查找走C3线性化算法确定的MRO路径,如D(B, C)且B、C均继承A时,D.mro()为[D, B, C, A, object],super()按此序列调用下一个类的方法。

Python多继承中属性查找走哪条路径
Python用MRO(Method Resolution Order)决定多继承下方法和属性的查找顺序,不是简单从左到右,也不是深度优先,而是C3线性化算法算出来的唯一有序列表。你写ClassName.mro()或ClassName.__mro__就能看到实际顺序,它直接影响super()行为和同名方法谁被调用。
为什么super()有时跳过父类、有时不按预期执行
super()不是“调上一级父类”,而是按当前类的MRO里**下一个类**去查找。如果多个父类有同名方法,最终调用哪个,完全取决于MRO序列中谁排在前面。
- 定义类
class D(B, C): pass,且B和C都继承自A,那么D.mro()是[D, B, C, A, object],不是[D, B, A, C, object] - 在
B.__init__()里写super().__init__(),会跳到C.__init__()(因为C在MRO中紧接在B之后),而非A.__init__() - 如果
C没实现__init__(),才会继续往后找——直到A
如何快速验证和调试MRO冲突
遇到“明明重写了方法却没生效”“super()报AttributeError”这类问题,第一反应不是改逻辑,而是看MRO是否符合直觉。
- 直接打印:
print(D.mro()),注意结果是元组,每个元素都是类对象 - 检查是否有菱形继承结构(B ← A, C ← A, D ← B, C),这是MRO易出错的高发场景
- 避免手动在
__init__里硬调A.__init__(self)——这绕过MRO,破坏协作式继承,后续加新父类时极易出错 - 若需强制调某个父类方法,用
ParentClass.method(self),但要清楚这脱离了super()链条
Python 2 和 Python 3 的MRO差异会影响代码迁移吗
Python 2 的经典类(不显式继承object)用深度优先遍历,而Python 3 所有类默认是新式类,统一用C3算法。所以只要你的类都明确继承object(如class A(object):)或使用Python 3,默认行为一致;但混用旧写法(如class A:)在Python 2/3间可能产生不同MRO。
立即学习“Python免费学习笔记(深入)”;
- Python 3 中
class A:等价于class A(object):,MRO可靠 - 跨版本兼容代码建议始终显式写
class A(object):,避免解释器推测 - 用
isinstance(obj, type)或issubclass(C, B)时,底层也依赖MRO,行为变化可能引发隐性bug
__mro__被动态修改(比如元类篡改),或者多重__bases__赋值,顺序就不可预测——这种操作极少见,也极危险。


















