第11章 继承与多态
学习目标
完成本章学习后,读者将能够:
- 理解Python继承机制与MRO(方法解析顺序)的工作原理
- 运用super()正确调用父类方法,理解协作式多继承
- 掌握Mixin模式实现代码复用的最佳实践
- 理解多态与鸭子类型的设计哲学
- 使用ABC和Protocol定义抽象接口与结构化类型
11.1 继承基础
11.1.1 单继承
class Animal:
def __init__(self, name: str):
self.name = name
def speak(self) -> str:
raise NotImplementedError("子类必须实现speak方法")
def info(self) -> str:
return f"I am {self.name}"
class Dog(Animal):
def speak(self) -> str:
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self) -> str:
return f"{self.name} says Meow!"
dog = Dog("Buddy")
print(dog.speak()) # "Buddy says Woof!"
print(isinstance(dog, Animal)) # True
print(issubclass(Dog, Animal)) # True11.1.2 super()与协作式调用
class Animal:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
class Dog(Animal):
def __init__(self, name: str, age: int, breed: str):
super().__init__(name, age) # 调用父类初始化
self.breed = breed
def info(self) -> str:
return f"{self.name}, {self.age}yo, {self.breed}"学术注记:
super()并非简单调用"父类方法",而是按照MRO顺序调用下一个类的方法。这使得多继承中的协作式调用成为可能。Python 3中super()无需参数,等价于super(__class__, self)。
11.1.3 方法重写与扩展
class Shape:
def __init__(self, color: str):
self.color = color
def area(self) -> float:
raise NotImplementedError
def describe(self) -> str:
return f"{self.color} shape, area={self.area():.2f}"
class Rectangle(Shape):
def __init__(self, color: str, width: float, height: float):
super().__init__(color)
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
class Circle(Shape):
def __init__(self, color: str, radius: float):
super().__init__(color)
self.radius = radius
def area(self) -> float:
import math
return math.pi * self.radius ** 2
shapes: list[Shape] = [Rectangle("red", 5, 3), Circle("blue", 4)]
for s in shapes:
print(s.describe())11.2 多继承与MRO
11.2.1 多继承
class Flyable:
def fly(self) -> str:
return "Flying!"
class Swimmable:
def swim(self) -> str:
return "Swimming!"
class Duck(Flyable, Swimmable):
def quack(self) -> str:
return "Quack!"
duck = Duck()
print(duck.fly()) # "Flying!"
print(duck.swim()) # "Swimming!"11.2.2 MRO(方法解析顺序)
class A:
def method(self):
print("A")
class B(A):
def method(self):
print("B")
super().method()
class C(A):
def method(self):
print("C")
super().method()
class D(B, C):
def method(self):
print("D")
super().method()
d = D()
d.method() # D → B → C → A
print(D.__mro__) # (D, B, C, A, object)学术注记:Python使用C3线性化算法计算MRO,保证:1)子类先于父类;2)按声明顺序遍历;3)对每个类只访问一次。菱形继承中,MRO确保
super()链不会重复调用任何类。
11.2.3 Mixin模式
class LogMixin:
def log(self, message: str) -> None:
print(f"[LOG] {self.__class__.__name__}: {message}")
class SerializableMixin:
def to_dict(self) -> dict:
return self.__dict__.copy()
class TimestampMixin:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
from datetime import datetime
self.created_at = datetime.now()
class Article(TimestampMixin, LogMixin, SerializableMixin):
def __init__(self, title: str, content: str):
super().__init__(title=title, content=content)
self.title = title
self.content = content
article = Article("Python", "Python is awesome!")
article.log("Article created")
print(article.to_dict())工程实践:Mixin类应遵循以下原则:1)不单独使用,仅用于多继承混入;2)不定义
__init__(或使用super().__init__协作);3)命名以Mixin结尾;4)保持单一职责。
11.3 多态
11.3.1 多态与鸭子类型
class Dog:
def speak(self) -> str:
return "Woof!"
class Cat:
def speak(self) -> str:
return "Meow!"
class Robot:
def speak(self) -> str:
return "Beep!"
def make_them_speak(speakers: list) -> None:
for s in speakers:
print(s.speak()) # 鸭子类型:只要有speak方法即可
make_them_speak([Dog(), Cat(), Robot()])学术注记:Python的多态基于鸭子类型——"如果它走起来像鸭子、叫起来像鸭子,那它就是鸭子"。与Java的静态多态(基于接口/继承)不同,Python不要求对象显式声明类型,只需实现所需方法即可。这是Python灵活性的核心来源。
11.3.2 协议式多态
# Python内置协议示例
class Story:
def __init__(self, title: str, content: str):
self.title = title
self.content = content
def __len__(self) -> int: # len协议
return len(self.content)
def __getitem__(self, index): # 迭代协议
return self.content[index]
story = Story("Hello", "Once upon a time...")
print(len(story)) # 20
for char in story[:5]: # 支持迭代和切片
print(char)11.4 抽象类与接口
11.4.1 ABC(抽象基类)
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float:
pass
@abstractmethod
def perimeter(self) -> float:
pass
def describe(self) -> str:
return f"Area: {self.area():.2f}, Perimeter: {self.perimeter():.2f}"
# Shape() # TypeError: 无法实例化抽象类
class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
def perimeter(self) -> float:
return 2 * (self.width + self.height)
rect = Rectangle(5, 3)
print(rect.describe())11.4.2 Protocol(结构化类型)
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def __init__(self, radius: float):
self.radius = radius
def draw(self) -> None:
print(f"Drawing circle (r={self.radius})")
class Square:
def __init__(self, side: float):
self.side = side
def draw(self) -> None:
print(f"Drawing square (side={self.side})")
def render(shape: Drawable) -> None:
shape.draw() # 任何有draw()方法的对象都符合
render(Circle(5)) # 无需继承Drawable
render(Square(4)) # 结构化类型检查学术注记:Protocol是结构化类型(Structural Typing)的实现——类型兼容性基于结构(方法签名)而非名义(继承关系)。这与ABC的名义类型(Nominal Typing)形成对比。Protocol更符合Python的鸭子类型哲学,同时提供静态类型检查支持。
11.4.3 ABC vs Protocol对比
| 特性 | ABC | Protocol |
|---|---|---|
| 类型检查 | 名义类型 | 结构化类型 |
| 运行时检查 | isinstance() | @runtime_checkable |
| 继承要求 | 必须显式继承 | 不需要 |
| 静态检查支持 | 是 | 是(mypy) |
| 适用场景 | 框架/库的强制约束 | 接口协议定义 |
11.5 设计模式实践
11.5.1 策略模式
from abc import ABC, abstractmethod
from typing import List
class SortStrategy(ABC):
@abstractmethod
def sort(self, data: List[int]) -> List[int]:
pass
class BubbleSort(SortStrategy):
def sort(self, data: List[int]) -> List[int]:
result = data.copy()
n = len(result)
for i in range(n):
for j in range(0, n - i - 1):
if result[j] > result[j + 1]:
result[j], result[j + 1] = result[j + 1], result[j]
return result
class QuickSort(SortStrategy):
def sort(self, data: List[int]) -> List[int]:
if len(data) <= 1:
return data
pivot = data[len(data) // 2]
left = [x for x in data if x < pivot]
middle = [x for x in data if x == pivot]
right = [x for x in data if x > pivot]
return self.sort(left) + middle + self.sort(right)
class Sorter:
def __init__(self, strategy: SortStrategy):
self._strategy = strategy
def set_strategy(self, strategy: SortStrategy) -> None:
self._strategy = strategy
def sort(self, data: List[int]) -> List[int]:
return self._strategy.sort(data)
sorter = Sorter(BubbleSort())
print(sorter.sort([3, 1, 4, 1, 5, 9, 2, 6]))
sorter.set_strategy(QuickSort())
print(sorter.sort([3, 1, 4, 1, 5, 9, 2, 6]))11.5.2 模板方法模式
from abc import ABC, abstractmethod
class DataProcessor(ABC):
def process(self, data: str) -> str:
data = self.read(data)
data = self.validate(data)
data = self.transform(data)
data = self.save(data)
return data
def read(self, data: str) -> str:
print(f"读取数据: {data}")
return data
@abstractmethod
def validate(self, data: str) -> str:
pass
@abstractmethod
def transform(self, data: str) -> str:
pass
def save(self, data: str) -> str:
print(f"保存数据: {data}")
return data
class JsonProcessor(DataProcessor):
def validate(self, data: str) -> str:
import json
json.loads(data)
print("JSON验证通过")
return data
def transform(self, data: str) -> str:
import json
obj = json.loads(data)
obj["processed"] = True
return json.dumps(obj)
class XmlProcessor(DataProcessor):
def validate(self, data: str) -> str:
print("XML验证通过")
return data
def transform(self, data: str) -> str:
return data.upper()
json_processor = JsonProcessor()
json_processor.process('{"name": "test"}')11.5.3 工厂模式
from abc import ABC, abstractmethod
from typing import Type
class Animal(ABC):
@abstractmethod
def speak(self) -> str:
pass
class Dog(Animal):
def speak(self) -> str:
return "Woof!"
class Cat(Animal):
def speak(self) -> str:
return "Meow!"
class AnimalFactory:
_registry: dict[str, Type[Animal]] = {}
@classmethod
def register(cls, name: str) -> callable:
def decorator(animal_class: Type[Animal]) -> Type[Animal]:
cls._registry[name] = animal_class
return animal_class
return decorator
@classmethod
def create(cls, name: str) -> Animal:
if name not in cls._registry:
raise ValueError(f"Unknown animal: {name}")
return cls._registry[name]()
@AnimalFactory.register("dog")
class RegisteredDog(Animal):
def speak(self) -> str:
return "Registered Woof!"
dog = AnimalFactory.create("dog")
print(dog.speak())11.5.4 组合模式
from abc import ABC, abstractmethod
from typing import List
class Component(ABC):
@abstractmethod
def operation(self) -> str:
pass
class Leaf(Component):
def __init__(self, name: str):
self.name = name
def operation(self) -> str:
return self.name
class Composite(Component):
def __init__(self, name: str):
self.name = name
self._children: List[Component] = []
def add(self, component: Component) -> None:
self._children.append(component)
def remove(self, component: Component) -> None:
self._children.remove(component)
def operation(self) -> str:
results = [child.operation() for child in self._children]
return f"{self.name}({', '.join(results)})"
root = Composite("root")
root.add(Leaf("A"))
branch = Composite("branch")
branch.add(Leaf("B"))
branch.add(Leaf("C"))
root.add(branch)
print(root.operation())11.6 知识图谱
11.6.1 Python继承体系
Python继承机制
单继承:
┌─────────────────────────────────────────┐
│ class Parent: │
│ def method(self): ... │
│ │
│ class Child(Parent): │
│ def method(self): │
│ super().method() # 调用父类 │
└─────────────────────────────────────────┘
多继承与MRO:
┌─────────────────────────────────────────┐
│ A │
│ / \ │
│ B C │
│ \ / │
│ D │
│ │
│ D.__mro__ = (D, B, C, A, object) │
│ C3线性化算法确定顺序 │
└─────────────────────────────────────────┘
Mixin模式:
┌─────────────────────────────────────────┐
│ class LogMixin: │
│ def log(self, msg): ... │
│ │
│ class ValidMixin: │
│ def validate(self): ... │
│ │
│ class MyClass(LogMixin, ValidMixin): │
│ pass # 组合多个功能 │
└─────────────────────────────────────────┘11.6.2 多态实现方式
Python多态机制
鸭子类型:
┌─────────────────────────────────────────┐
│ "如果它走起来像鸭子,叫起来像鸭子, │
│ 那么它就是鸭子" │
│ │
│ def process(obj): │
│ obj.method() # 不检查类型 │
│ │
│ # 任何有method()的对象都可以传入 │
└─────────────────────────────────────────┘
协议式多态 (Protocol):
┌─────────────────────────────────────────┐
│ class Drawable(Protocol): │
│ def draw(self) -> None: ... │
│ │
│ def render(obj: Drawable): │
│ obj.draw() │
│ │
│ # 静态类型检查,运行时无约束 │
└─────────────────────────────────────────┘
抽象基类 (ABC):
┌─────────────────────────────────────────┐
│ class Shape(ABC): │
│ @abstractmethod │
│ def area(self) -> float: ... │
│ │
│ # 子类必须实现area() │
│ # 运行时强制约束 │
└─────────────────────────────────────────┘11.6.3 MRO计算示例
C3线性化算法示例
菱形继承:
A
/ \
B C
\ /
D
计算过程:
L[A] = [A, object]
L[B] = [B] + merge(L[A], [A])
= [B] + merge([A, object], [A])
= [B, A, object]
L[C] = [C, A, object]
L[D] = [D] + merge(L[B], L[C], [B, C])
= [D] + merge([B, A, object], [C, A, object], [B, C])
= [D, B] + merge([A, object], [C, A, object], [C])
= [D, B, C] + merge([A, object], [A, object])
= [D, B, C, A, object]
验证: D.__mro__ == (D, B, C, A, object)11.6.4 设计模式分类
OOP设计模式速查
创建型模式:
┌─────────────────────────────────────────┐
│ 工厂方法 定义创建对象的接口 │
│ 抽象工厂 创建相关对象家族 │
│ 单例 确保只有一个实例 │
│ 建造者 分步骤构建复杂对象 │
│ 原型 克隆已有对象 │
└─────────────────────────────────────────┘
结构型模式:
┌─────────────────────────────────────────┐
│ 适配器 转换接口 │
│ 桥接 分离抽象与实现 │
│ 组合 树形结构 │
│ 装饰器 动态添加功能 │
│ 外观 简化接口 │
│ 代理 控制访问 │
└─────────────────────────────────────────┘
行为型模式:
┌─────────────────────────────────────────┐
│ 策略 可互换的算法 │
│ 模板方法 定义算法骨架 │
│ 观察者 发布-订阅 │
│ 迭代器 遍历集合 │
│ 命令 封装请求 │
│ 状态 状态机 │
└─────────────────────────────────────────┘11.7 技术选型指南
11.7.1 继承vs组合选型
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| is-a关系 | 继承 | 语义清晰 |
| has-a关系 | 组合 | 灵活解耦 |
| 共享代码 | Mixin | 避免继承链 |
| 运行时切换 | 组合 | 可替换组件 |
| 扩展功能 | 装饰器模式 | 开闭原则 |
11.7.2 多态机制选型
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 简单多态 | 鸭子类型 | 简洁灵活 |
| 需要类型检查 | Protocol | 静态检查 |
| 强制实现 | ABC | 运行时约束 |
| 接口文档 | Protocol | IDE支持好 |
| 框架设计 | ABC + Protocol | 兼顾两者 |
11.7.3 Mixin设计原则
| 原则 | 说明 |
|---|---|
| 单一功能 | 每个Mixin只做一件事 |
| 无状态 | 避免实例属性 |
| 不继承除object外 | 保持简单 |
| 命名以Mixin结尾 | 约定清晰 |
| 方法独立 | 不依赖其他Mixin |
11.7.4 super()使用指南
| 场景 | 用法 |
|---|---|
| 单继承 | super().method() |
| 多继承协作 | super().init(**kwargs) |
| 获取父类属性 | super().attribute |
| 调用父类方法 | super().method() |
11.8 常见问题与解决方案
11.8.1 super()调用问题
# 问题:多继承中super()调用混乱
class A:
def __init__(self):
print("A")
class B(A):
def __init__(self):
print("B")
super().__init__() # 调用C还是A?
class C(A):
def __init__(self):
print("C")
super().__init__()
class D(B, C):
def __init__(self):
print("D")
super().__init__()
# 解决方案:理解MRO
# D.__mro__ = (D, B, C, A, object)
# super()按MRO顺序调用下一个类
d = D() # D -> B -> C -> A11.8.2 菱形继承问题
# 问题:菱形继承导致基类多次初始化
class A:
def __init__(self):
print("A init")
class B(A):
def __init__(self):
A.__init__(self) # 直接调用
print("B init")
class C(A):
def __init__(self):
A.__init__(self) # 直接调用
print("C init")
class D(B, C):
def __init__(self):
B.__init__(self)
C.__init__(self)
print("D init")
d = D() # A init 打印两次!
# 解决方案:使用super()协作调用
class A:
def __init__(self):
print("A init")
class B(A):
def __init__(self):
super().__init__()
print("B init")
class C(A):
def __init__(self):
super().__init__()
print("C init")
class D(B, C):
def __init__(self):
super().__init__() # 只调用一次
print("D init")11.8.3 抽象方法未实现
from abc import ABC, abstractmethod
# 问题:忘记实现抽象方法
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
# 忘记实现area()
# c = Circle(1) # TypeError: Can't instantiate abstract class
# 解决方案:确保实现所有抽象方法
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 211.8.4 Mixin状态污染
# 问题:Mixin使用实例属性导致冲突
class CounterMixin:
def __init__(self):
self.count = 0 # 可能与其他Mixin冲突
def increment(self):
self.count += 1
# 解决方案:使用命名空间或前缀
class CounterMixin:
_counter_count: int = 0
def counter_increment(self):
self._counter_count += 1
return self._counter_count11.8.5 Protocol运行时检查
from typing import Protocol, runtime_checkable
# 问题:Protocol默认不支持isinstance检查
class Drawable(Protocol):
def draw(self) -> None: ...
# 解决方案:添加@runtime_checkable
@runtime_checkable
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("Drawing circle")
c = Circle()
print(isinstance(c, Drawable)) # True11.9 本章小结
11.6.1 结构化子类型(PEP 544)
from typing import Protocol, runtime_checkable
@runtime_checkable
class Drawable(Protocol):
def draw(self) -> None: ...
def render(obj: Drawable) -> None:
obj.draw()
class Circle:
def draw(self) -> None:
print("Drawing circle")
render(Circle())11.6.2 类型系统增强
from typing import Self, TypeVar, Generic
T = TypeVar('T')
class Container(Generic[T]):
def __init__(self, value: T):
self.value = value
def map(self, f: callable[[T], T]) -> Self:
return type(self)(f(self.value))11.6.3 组合优于继承
from dataclasses import dataclass
@dataclass
class FlyBehavior:
def fly(self) -> str:
return "Flying"
@dataclass
class QuackBehavior:
def quack(self) -> str:
return "Quacking"
class Duck:
def __init__(self):
self.fly_behavior = FlyBehavior()
self.quack_behavior = QuackBehavior()11.6.4 模式匹配与多态
from dataclasses import dataclass
@dataclass
class Success:
value: int
@dataclass
class Failure:
error: str
def handle_result(result: Success | Failure) -> str:
match result:
case Success(value=v):
return f"Success: {v}"
case Failure(error=e):
return f"Error: {e}"11.9 本章小结
本章系统介绍了Python继承与多态的完整体系:
- 继承:单继承、super()协作调用、方法重写与扩展
- 多继承:MRO(C3线性化)、Mixin模式最佳实践
- 多态:鸭子类型、协议式多态、灵活的消息传递
- 抽象:ABC强制约束、Protocol结构化类型
- 设计模式:策略模式、模板方法、工厂模式、组合模式
11.9.1 继承设计原则
| 原则 | 说明 | 建议 |
|---|---|---|
| 组合优于继承 | 继承是强耦合 | 优先使用has-a关系 |
| 里氏替换原则 | 子类可替换父类 | 子类不应违反父类契约 |
| 接口隔离 | 接口要小而专 | 多个小接口优于一个大接口 |
| 依赖倒置 | 依赖抽象而非具体 | 面向接口编程 |
| 单一职责 | 类只有一个变化原因 | 避免上帝类 |
11.9.2 常见陷阱与规避
# 陷阱1:继承层次过深
class A: pass
class B(A): pass
class C(B): pass
class D(C): pass # 难以维护!
# 正确做法:使用组合
class Component:
def operation(self): pass
class Object:
def __init__(self, component: Component):
self.component = component
# 陷阱2:滥用多继承
class A:
def method(self): print("A")
class B(A):
def method(self): print("B")
class C(A):
def method(self): print("C")
class D(B, C): # MRO复杂
pass
# 正确做法:使用Mixin
class LogMixin:
def log(self): pass
class ValidMixin:
def validate(self): pass
class MyClass(LogMixin, ValidMixin):
pass
# 陷阱3:忘记调用super().__init__()
class Parent:
def __init__(self, value):
self.value = value
class Child(Parent):
def __init__(self, value, extra):
# 忘记super().__init__(value)
self.extra = extra
# 正确做法
class Child(Parent):
def __init__(self, value, extra):
super().__init__(value)
self.extra = extra11.10 练习题
基础题
创建Vehicle基类,派生Car和Bicycle类,各自实现移动方式描述。
使用多态实现图形面积计算器,支持矩形、圆形和三角形。
创建抽象类Shape,要求子类实现area()和perimeter()。
进阶题
实现LogMixin和TimestampMixin,为任意类添加日志和时间戳功能。
使用Protocol定义Iterator接口,并实现自定义迭代器。
实现一个简单的插件系统,使用ABC定义插件接口,支持动态加载。
项目实践
- 图形编辑器框架:编写一个程序,要求:
- 使用ABC定义Shape接口(area、perimeter、draw、resize)
- 实现Rectangle、Circle、Triangle具体图形
- 使用Mixin添加Serializable和Comparable功能
- 使用Protocol定义Renderer接口
- 支持Canvas类管理多个图形,计算总面积
- 实现图形的序列化与反序列化
思考题
Python的MRO为什么使用C3线性化?菱形继承中super()是如何工作的?
Mixin模式与普通多继承有什么区别?什么情况下应使用Mixin?
Protocol相比ABC有什么优势?在什么场景下应优先使用Protocol?
11.11 延伸阅读
11.11.1 面向对象设计
- 《设计模式:可复用面向对象软件的基础》 (GoF) — 23种经典设计模式
- 《Head First设计模式》 — 设计模式入门经典
- 《敏捷软件开发:原则、模式与实践》 (Robert C. Martin) — OOP实践指南
- SOLID原则详解 — 面向对象设计的五大原则
11.11.2 Python继承机制
- PEP 3135 — New Super (https://peps.python.org/pep-3135/) — Python 3 super()语法
- Python MRO文档 (https://www.python.org/download/releases/2.3/mro/) — C3线性化算法
- **《Fluent Python》第12-14章》 — 继承与多态深度解析
11.11.3 类型系统
- PEP 544 — Protocols (https://peps.python.org/pep-0544/) — 结构化子类型
- PEP 3119 — Abstract Base Classes (https://peps.python.org/pep-3119/) — ABC规范
- mypy Protocol文档 (https://mypy.readthedocs.io/en/stable/protocols.html) — 静态类型检查
11.11.4 设计模式资源
- Refactoring Guru (https://refactoring.guru/design-patterns) — 设计模式可视化教程
- Python Patterns (https://github.com/faif/python-patterns) — Python设计模式集合
- 《Python设计模式》 (Dusty Phillips) — Python设计模式实践
下一章:第12章 高级面向对象特性