子类中调用被覆盖的父类方法必须显式使用super(),否则父类逻辑被彻底替换;重写__init__时漏掉super().__init__()会导致父类初始化失效;多重继承下super()按MRO顺序查找方法。

子类中调用被覆盖的父类方法必须显式写 super()
Python 不会自动保留父类方法的引用,一旦子类定义了同名方法,父类版本就完全不可见——除非你主动调用。这不是“覆盖后还能默认回退”,而是彻底替换。
常见错误是以为写个 self.method_name() 就能触发父类逻辑,结果只是递归调用自己,最终爆 RecursionError 或静默错乱。
- 正确姿势永远是
super().method_name()(Python 3 推荐)或ParentClass.method_name(self)(需明确指定父类,不推荐) -
super()在多重继承中更可靠,它按 MRO 顺序找下一个实现,不是硬编码父类 - 如果父类方法带参数,子类调用时必须传全,
super().process(data, verbose=True)不能漏掉verbose
重写 __init__ 时漏掉 super().__init__() 是高频崩溃点
很多初学者在子类里加了新属性就以为完事了,结果父类的初始化逻辑(比如设置 self._cache、打开文件、校验参数)全被跳过,后续调用直接抛 AttributeError 或状态异常。
典型症状:AttributeError: 'Child' object has no attribute '_config',但父类明明在 __init__ 里赋值了。
立即学习“Python免费学习笔记(深入)”;
- 只要父类
__init__做了任何初始化工作,子类就必须调用super().__init__(...) - 参数要对齐:如果父类
__init__(self, name, timeout=30),子类不能只传name而丢掉timeout,除非你显式提供默认值 - 调用位置通常放在子类
__init__开头,避免依赖未初始化的父类状态
想“增强”而非“替代”父类方法?用模板方法模式 + super()
如果你的需求是“执行父类逻辑,再加点自己的处理”,别写两个独立方法,直接在子类方法里嵌入 super() 调用——这是最轻量、最符合 Python 习惯的做法。
例如日志记录、权限检查、结果包装这类横切关注点,没必要抽象成装饰器或钩子函数,先看 super() 能不能干净解决。
- 父类方法返回值需要加工?接住它:
result = super().fetch(); return result.strip() - 想在父类逻辑前后插入操作?
self._log_start(); super().run(); self._log_end() - 避免在子类里复制父类全部逻辑再改几行——维护成本陡增,且容易因父类更新而脱节
多重继承下 super() 行为取决于 MRO,不是直系父类
当类继承自多个父类(如 class Child(A, B):),super().method() 找的不是 A,而是 MRO 序列中当前类之后的**第一个有该方法的类**。这常导致预期外的调用链。
查 MRO 很简单:Child.__mro__ 或 Child.mro(),输出类似 (Child, A, B, object)。
- 如果
A和B都实现了save(),super().save()在Child中调用的是A.save(),因为A在 MRO 中排B前面 - 想强制调用
B.save()?不能靠super(),得写B.save(self),但这破坏了协作契约,慎用 - 所有参与多重继承的类,其方法都应以
super()结尾(哪怕只是super().__init__()),否则调用链会在某处中断
真正麻烦的从来不是语法怎么写,而是没意识到“覆盖即切断”这个前提——Python 的方法解析是动态且严格的,没有隐式 fallback。每次重写方法前,先问一句:我是不是真的要扔掉父类那部分逻辑?如果不是,super() 就不是可选项,是必选项。


















