苦练Python第47天:一文吃透继承与多继承
🧬 继承的本质:把公共代码薅出来复用
1 2 3 4 5 6 7 8 9 10 11
| class Animal: # 父类(基类) def __init__(self, name): self.name = name def speak(self): return "???" class Dog(Animal): # 子类(派生类) def speak(self): return f"{self.name}: 汪汪!" >>> d = Dog("旺财") >>> d.speak() 旺财: 汪汪!
|
结论:子类自动拥有父类所有公共属性和方法。
注意:Python 默认所有方法都是 virtual(C++ 术语),想重写就重写。
🔁 方法重写 & 扩展:子类想加料怎么办?
1 2 3 4 5 6 7
| class Cat(Animal): def speak(self): base = super().speak() # 先把父类的结果薅过来 return f"{base} → 喵喵~" # 再加点私货 >>> c = Cat("咪咪") >>> c.speak() ??? → 喵喵~
|
super() 的 3 个用处:
- 调用父类被覆盖的方法
- 在多重继承链里按 MRO 顺序调用
- 避免硬编码父类名,方便重构
🌲 多重继承:一娃多爹,爽还是坑?
1 2 3 4 5 6 7 8 9
| class Flyable: def fly(self): return "I can fly!"
class Bird(Animal, Flyable): # 逗号分隔,多爹 pass >>> b = Bird("啾啾") >>> b.speak(), b.fly() ('啾啾: ???', 'I can fly!')
|
真相:Python 支持无限多继承,但顺序很重要!
🔍 MRO(方法解析顺序):Python 的“族谱算法”
1 2 3 4 5 6 7 8 9 10 11 12 13
| class A: def hi(self): print("A")
class B(A): def hi(self): print("B")
class C(A): def hi(self): print("C")
class D(B, C): pass >>> D.__mro__ (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
|
口诀:从左到右,深度优先,留坑不回头。
有重叠(菱形继承)时,Python 用 C3 线性化保证每个祖先只出现一次。
💎 菱形陷阱 & super 连环call 自救
错误示范:父类被多次初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Base: def __init__(self): print("Base init")
class Left(Base): def __init__(self): Base.__init__(self) print("Left init")
class Right(Base): def __init__(self): Base.__init__(self) print("Right init")
class Bottom(Left, Right): def __init__(self): Left.__init__(self) Right.__init__(self)
>>> Bottom() Base init Left init Base init # 悲剧:Base 被调了两次 Right init
|
正确姿势:super() 一条龙
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Base: def __init__(self): print("Base init")
class Left(Base): def __init__(self): super().__init__() print("Left init")
class Right(Base): def __init__(self): super().__init__() print("Right init")
class Bottom(Left, Right): def __init__(self): super().__init__() print("Bottom init")
>>> Bottom() Base init Right init Left init Bottom init
|
解释:
- 每个类都调用
super() 交给 MRO 下一棒
- 整个链条只跑一次,Base 只初始化一次
🧰 工具函数:快速判断血缘
| 需求 |
代码 |
| 实例是否属于某类 |
isinstance(obj, cls) |
| 类是否继承某类 |
issubclass(cls1, cls2) |
| 查看 MRO |
cls.__mro__ 或 help(cls) |
🧾 速查表
| 场景 |
关键语法/技巧 |
| 单继承 |
class Child(Parent): |
| 重写方法 |
def method(self): ... |
| 扩展父类 |
super().method() |
| 多继承 |
class C(A, B): |
| 避免重复初始化 |
全部用 super() |
| 查看调用顺序 |
cls.__mro__ |
✅ 一句话总结
单继承让代码复用,多继承让功能拼乐高;
牢记 super() + MRO,就能在多重继承的迷宫里不迷路!
https://mp.weixin.qq.com/s/slOLyNIIYaKkIlyUEMdFLA?scene=1