是,super()严格按当前类的__mro__顺序查找下一个类的同名方法;若父类方法被跳过、重复或未触发,根源在于继承顺序或super()缺失导致mro链断裂,需打印__mro__验证并确保所有参与类统一使用super()透传。

super() 调用不按预期执行,是不是 MRO 没搞对?
不是 super() 有问题,是它严格按当前类的 __mro__ 顺序往后找下一个类的同名方法。如果你看到父类方法被跳过、重复执行或根本没触发,大概率是类定义时继承顺序或 super() 放置位置不对。
关键判断:打印 Cls.__mro__,确认你期望被调用的那个类,确实在当前类之后、且是第一个匹配到该方法名的位置。
- 多继承中,MRO 使用 C3 线性化算法,不是简单从左到右或深度优先
-
super()在类方法里等价于super(CurrentClass, self),它查的是self.__class__.__mro__,不是定义该方法的类的 MRO - 所有参与链式调用的类,都必须显式写
super().__init__()(或其他方法),缺一个就会断链
为什么 A(B, C) 和 A(C, B) 的 MRO 完全不同?
Python 的 MRO 不是静态“父类列表”,而是整个继承图的拓扑排序结果。交换基类顺序会改变 C3 合并过程,导致中间类插入位置变化。
例如:
class A: pass class B(A): pass class C(A): pass class D(B, C): pass print(D.__mro__) # (<class>, <class>, <class>, <class>, <class>)</class></class></class></class></class>
但把 D(B, C) 改成 D(C, B),B 就会掉到 A 后面,破坏你预设的初始化顺序。
- 用
python -c "print(D.__mro__)”快速验证,别靠猜 - 如果某个父类的
__init__需要最先/最后运行,把它放在继承列表最左/最右,并确保所有中间类都转发super() - 避免让两个无关联父类都继承自同一祖类(如都继承
A),否则容易触发 “钻石问题” 中的重复调用
在 __init__ 里漏写 super().__init__() 会发生什么?
链直接断掉。后面所有类的 __init__ 都不会被调用,哪怕它们在 MRO 里排得很靠前。
典型症状:对象缺少某些父类设置的属性、日志没打、资源没初始化——但又不报错。
- 只要参与多继承协作,每个类的
__init__都应以super().__init__(...)结尾(或至少调用它) - 参数需保持一致:如果父类
__init__接收**kwargs,下游也得透传,否则关键字参数会在某一层被吃掉 - 不要混用显式调用(如
B.__init__(self))和super();二者逻辑冲突,MRO 失效
想绕过 MRO 强制调某个父类方法,能不能用 Parent.method(self)?
能,但这不是“绕过”,是放弃协作机制。它会跳过 MRO 中该父类之后的所有类,包括本该由它们完成的职责。
比如 A(B, C) 中,你在 A.__init__ 里写 C.__init__(self),那 B.__init__ 就永远不会执行——即使它在 MRO 里位于 C 前面。
- 仅在明确不需要协作、且确定调用路径时使用显式父类调用
- 一旦用了显式调用,就别在同一个方法里再混
super(),语义混乱 - 调试时临时加
print比硬编码调用更安全;真要跳过某层,优先考虑重构继承关系,而不是强行跳转
MRO 是隐式的,super() 是它的执行引擎,两者绑定极紧。最容易被忽略的,是认为“写了 super() 就万事大吉”,而没检查所有参与类是否真正构成一条完整、参数兼容的调用链。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











