super()能避免菱形继承中父类方法重复执行,因其按MRO顺序自动调用下一个类的方法,确保Base.__init__()仅执行一次;所有参与类必须统一使用super(),否则链式调用会静默中断。

super() 能避免菱形继承中父类方法被重复执行
当类结构是 C(A, B) 且 A 和 B 都继承自 Base 时,如果 A.__init__(self) 和 B.__init__(self) 都显式调用 Base.__init__,Base.__init__() 就会运行两次。而 super().__init__() 按 MRO(如 (C, A, B, Base, object))顺序自动跳转到下一个类,只触发一次 Base.__init__()。
这种重复执行在初始化资源(如打开文件、连接数据库)时会导致严重问题——比如连接被意外关闭两次,或日志写入重复条目。
super() 不依赖硬编码的父类名,支持动态继承链
直接写 ParentClass.method(self) 把父类名写死了。一旦重构时把 ParentClass 改成 BaseClass,所有子类里都要手动改;混入类(Mixin)插入到继承链中间时,这种写法会完全失效。
super() 是基于当前类在 MRO 中的位置动态查找“下一个”类,所以:
立即学习“Python免费学习笔记(深入)”;
- 类名变更不影响调用逻辑
- Mixin 类可以安全插入(只要它也用
super()) - 继承顺序调整后仍能保持协作一致性
所有参与类必须统一使用 super(),否则调用链会静默中断
这是最容易被忽略的关键点:如果 A 用 super(),B 却用 Parent.__init__(self),那么 MRO 中 B 后面的类(比如 Base)就永远不会被调用——没有报错,但逻辑漏执行。
验证方式很简单:C.__mro__ 查出顺序后,逐个检查每个类的 __init__ 是否都用了 super()。只要有一个掉队,整个链就断了。
常见错误包括:
- 在静态方法中误用
super()(会抛RuntimeError) - 参数不匹配:父类方法要求两个参数,
super().method(x)只传了一个 - 在类外部(如模块顶层)调用
super()
super() 在非 __init__ 方法中同样关键
很多人只在构造函数里注意 super(),却在重写 __str__、__eq__、__get__ 或普通业务方法时又切回硬编码写法。
比如自定义描述符里写 BaseDescriptor.__get__(self, obj, cls),就绕过了 MRO,导致上级描述符逻辑丢失;重写 display() 时漏掉 super().display(),会让基础格式化能力消失。
真正要生效,得在所有需要沿继承链向上委托的地方都用 super()——不只是 __init__,也不只是实例方法。
复杂点在于:MRO 是运行时确定的,而 super() 的行为完全取决于调用位置和参与类是否协同。一个类加了 Mixin、另一个没改,整条链就可能失效。这种隐式依赖很难靠测试覆盖,只能靠约定和代码审查守住。


















