Python 继承、方法重写与 super
说明 Python 中继承如何复用行为,方法重写如何扩展父类逻辑,以及 super 为什么表示沿 MRO 向后协作而不只是“调父类”。
#type / concept
#status / growing
#resource / python
#tech / lang / python
[!info] related notes
- 所属 MOC: Python 类与面向对象 MOC
- 前置概念: python实例方法类方法与静态方法
- 并列概念: Python 多重继承与 MRO
- 易混淆概念: 鸭子类型
- 关系笔记: python类与面向对象
Python 继承、方法重写与 super
一句话定义
继承让子类复用父类已有状态和行为,方法重写让子类改写同名行为,而 super() 的真正含义是“沿当前 MRO 找下一个实现继续协作”。
核心机制 / 工作原理
1. 继承表达的是“在已有基础上继续定义”
当 class Child(Parent): 出现时,子类会继承父类的一部分属性和方法。这样做的价值不是少写几行代码,而是让“共性行为”集中定义,“差异行为”留给子类扩展。
2. 方法重写是在子类里重新定义同名行为
如果子类定义了和父类同名的方法,实例调用时会优先用子类实现。这让子类既可以:
- 完全替换父类行为
- 或者在父类行为前后加上自己的逻辑
3. super() 不是“硬编码调用父类”
很多人把 super() 理解成“去调直接父类”,这在简单例子里看起来像对的,但更准确的说法是:
super() 会按照当前类的 MRO,去找“下一个应该被调用的实现”。
这也是它能在多重继承里协作的根本原因。
4. 初始化也应该遵守协作式调用
如果子类重写 __init__,通常也应该先用 super().__init__(...) 初始化父类部分状态,再补自己的字段。这样能保证整条继承链的初始化顺序清晰,也为以后扩展成多重继承保留空间。
最小例子 / 最小场景
class Person:
def __init__(self, name: str):
self.name = name
def introduce(self) -> str:
return f"I am {self.name}"
class Employee(Person):
def __init__(self, name: str, employee_id: str):
super().__init__(name)
self.employee_id = employee_id
def introduce(self) -> str:
base = super().introduce()
return f"{base}, employee id = {self.employee_id}"
e = Employee("Alice", "E-01")
print(e.introduce())
这里 Employee 没有重复定义 name 的初始化逻辑,而是复用了 Person 的构造过程;introduce 则通过 super() 把父类结果拼接成更具体的版本。
边界与易混淆点
- 直接写
Parent.method(self, ...)会把依赖关系写死,后续一旦进入多重继承,就可能破坏协作链。 - 重写方法时最好保持输入输出语义稳定,否则“看起来是子类,实际上换了契约”,可替换性会很差。
- 如果你的目标只是“组合两个对象协作”,而不是表达清晰的层级复用关系,组合通常比继承更稳。