super()查找的是MRO中“下一个类”而非直接父类,依据C3线性化算法确定的继承顺序,从当前类在__mro__中的位置向后查找第一个实现该方法的类,要求所有同名方法统一使用super()以保障协作式多重继承。

super() 查找的是 MRO 中“下一个类”,不是父类
调用 super().__init__() 时,Python 不会去找直接父类,而是从当前类在 __mro__ 元组中的位置往后扫描,取**第一个有该方法的类**。比如 D(B, C) 的 MRO 是 (<class>, <class>, <class>, <class>, <class>)</class></class></class></class></class>,那么在 B.__init__() 里写 super().__init__(),实际查找起点是 C,不是 A。
常见错误现象:以为 super() 总是调 B 的父类 A,结果发现 C.__init__() 被执行了——这就是因为 MRO 把 C 排在 A 前面。
- 必须用
self.__class__.__mro__实时看顺序,不能靠继承声明“猜” - 如果某个类没用
super(),而是硬写A.__init__(self),MRO 链就断了,后续类(如C)的__init__永远不会被触发 -
super()在类方法中需显式传参:super(Cls, cls).method(),否则可能查错 MRO
不按 MRO 走会导致初始化遗漏或重复
多重继承中,各父类常各自负责一部分初始化逻辑(比如日志、连接、配置加载)。只有所有类都统一用 super(),才能让每个 __init__ 恰好执行一次,且顺序可控。
使用场景:写混合类(Mixin)、框架插件、ORM 字段组合等需要叠加行为的地方。
立即学习“Python免费学习笔记(深入)”;
- 混用
Parent.__init__(self)和super()→ 某些类的__init__被跳过 - 漏掉某个父类的
super()→ 后续所有类的初始化中断 - 性能影响不大,但逻辑错误极难定位;打印每步的
self.__class__.__name__是最有效的调试手段
查看和验证 MRO 的几种可靠方式
别信直觉,直接看运行时结果。MRO 是动态计算的,哪怕只改一个父类的继承关系,整个顺序都可能变。
- 用
D.__mro__看元组(只读,最常用) - 用
D.mro()看列表(可修改,但不建议) - 在方法里加
print(self.__class__.__mro__),确认当前实例的真实链 - 注意:即使没显式继承
object,Python 3 中它也总在 MRO 末尾
C3 算法不是深度优先也不是广度优先
有人记成“从左到右、深度优先”,这是错的。C3 是线性合并算法,核心约束是:子类一定在父类前、声明顺序必须保留、每个类只出现一次。它能处理 B 和 C 都继承 A 的情况,把 A 推到最后,避免重复。
容易踩的坑:看到 class D(B, C): pass 就默认先走 B→A,再走 C→A,其实 C3 会把 A “压到底部”,确保它只被初始化一次。
真正复杂的地方在于,MRO 是在类定义时就计算好的,但 super() 的行为依赖于运行时的实例类型——如果你用 super() 在类方法中,又没传对第二个参数,查的就不是你期望的那个 MRO。


















