根本原因是继承链或方法解析逻辑出现循环引用,如MRO异常、父类名误写、多继承设计不当或super()错误指向当前类,导致无限递归和栈溢出。

在复杂继承体系中,super() 调用引发栈溢出,根本原因不是 super 本身有问题,而是继承链或方法解析逻辑出现了循环引用——比如 MRO(Method Resolution Order)异常、父类名误写、多继承设计不当,或 super() 被错误地指向当前类而非上一级。这种“自我调用”会让方法反复进入自身,无限压栈,最终触发 RecursionError。
检查并修正 MRO 顺序
MRO 决定了 super() 向谁查找下一个方法。如果 MRO 中出现重复类、断裂或意外回环(如 A → B → C → A),super() 就可能绕回当前类。
- 用
ClassName.mro()打印完整继承路径,确认没有重复或非预期回跳 - 避免手动修改
__mro__或动态篡改类结构 - 多重继承时,确保所有父类都遵循相同的协作协议(例如全部使用
super().__init__())
杜绝显式 self.super 或动态 super 字段
某些框架或手写继承逻辑中,会把 self.super 当作属性赋值(如 self.super = super()),这在实例间共享或重入时极易失效,导致后续调用回到当前类。
- 始终在需要处**即时调用**
super(),不要缓存为实例属性 - 避免在
__init__外的其他方法中做类似self.super = super(Child, self)的操作 - 若需复用,可封装为局部变量(如
parent = super()),但仅限当前作用域内使用
用显式父类名替代 super(谨慎但有效)
当继承关系明确、稳定且不常变动时,直接调用父类方法反而更可控,彻底规避 MRO 解析风险。
- 例如:
A.__init__(self, ...)替代super().__init__(...) - 适用于单继承主导、或调试阶段快速定位问题的场景
- 注意:若未来改为多继承,需同步更新所有显式调用,维护成本略高
添加调用日志与防护断言
在关键初始化或钩子方法中加入轻量级防御机制,提前捕获异常调用模式。
- 记录每次
super()调用前的self.__class__.__name__和目标类名 - 在
__init__开头加断言:assert self.__class__ is not ParentClass, "super() resolved to self" - 对高频/递归倾向的方法(如
__getattribute__),考虑用装饰器限制嵌套深度
这类问题不复杂但容易忽略,关键在于让每次 super() 都落在预期的父类上,而不是兜一圈又回到自己。

















