super() 按 mro 动态调用下一方法,确保钻石继承中基类初始化仅一次且适配继承顺序变化;硬写 parentclass.method(self) 会破坏 mro 协作,导致重复/漏调、参数错乱。

super() 与 ParentClass.method(self) 的调用行为差异
两者根本不是等价替换。用 ParentClass.method(self) 是硬编码跳转到某个具体类,而 super() 是按当前类的 __mro__ 动态查找“下一个”类的方法。在多重继承中,这个“下一个”可能不是你直觉里的父类——比如 class C(A, B): 中,C.__mro__ 是 (C, A, B, object),那么 super().__init__() 在 A.__init__ 里会继续调 B.__init__,而不是停在 A 就结束。
显式写父类名导致 MRO 变更后逻辑断裂
当你把 A.__init__(self) 写死在某个混入类里,后续如果调整继承顺序(比如把 class D(B, A): 改成 class D(A, B):),MRO 就变了,但那行硬写的 A.__init__ 还在原地执行——它可能重复调用、漏掉关键初始化,甚至触发 TypeError(参数不匹配)。而 super() 会自动适配新 MRO 链,只要每个类都参与协作,整个链就不断。
- 检查方式:运行
ClassName.__mro__看实际顺序,别靠名字猜 - 所有参与该方法的类(包括 mixin)都应包含
super().method_name(),哪怕空实现也要写 - 混用
Parent.method(self)和super()是高危操作,容易造成重复或跳过
钻石继承下重复初始化的风险
当多个父类共同继承自同一个基类(如 class A(Base): class B(Base): class C(A, B):),用 super() 能确保 Base.__init__ 只执行一次;但若在 A 和 B 中都写 Base.__init__(self),C 实例化时就会调两次 Base.__init__,可能引发资源重复分配、状态覆盖等问题。
这不是理论风险——常见于数据库连接池、日志 handler 注册、全局计数器等有副作用的初始化逻辑。
参数传递混乱的根源
多重继承中各父类 __init__ 所需参数往往不同。用 super() 配合 **kwargs 可让参数“穿透”整条链;而硬写 Parent.__init__(self, x, y) 会强制绑定参数结构,一旦新增父类或调整顺序,就得同步改所有显式调用点,维护成本陡增。
真正难处理的从来不是语法,而是当某天有人把 class Child(ParentA, ParentB) 改成 class Child(ParentB, ParentA) 后,没人记得去翻 ParentA.__init__ 里那行 ParentB.__init__(self, ...) 已经失效了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











