第11章 继承与多态

学习目标

完成本章学习后,读者将能够:

  • 理解Python继承机制与MRO(方法解析顺序)的工作原理
  • 运用super()正确调用父类方法,理解协作式多继承
  • 掌握Mixin模式实现代码复用的最佳实践
  • 理解多态与鸭子类型的设计哲学
  • 使用ABC和Protocol定义抽象接口与结构化类型

11.1 继承基础

11.1.1 单继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)) # True

11.1.2 super()与协作式调用

1
2
3
4
5
6
7
8
9
10
11
12
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 方法重写与扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 多继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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(方法解析顺序)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 多态与鸭子类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 协议式多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 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(抽象基类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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(结构化类型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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对比

特性ABCProtocol
类型检查名义类型结构化类型
运行时检查isinstance()@runtime_checkable
继承要求必须显式继承不需要
静态检查支持是(mypy)
适用场景框架/库的强制约束接口协议定义

11.5 设计模式实践

11.5.1 策略模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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 模板方法模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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 工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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 组合模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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 结构化子类型(PEP 544)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 类型系统增强

1
2
3
4
5
6
7
8
9
10
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 组合优于继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 模式匹配与多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.7 本章小结

本章系统介绍了Python继承与多态的完整体系:

  1. 继承:单继承、super()协作调用、方法重写与扩展
  2. 多继承:MRO(C3线性化)、Mixin模式最佳实践
  3. 多态:鸭子类型、协议式多态、灵活的消息传递
  4. 抽象:ABC强制约束、Protocol结构化类型
  5. 设计模式:策略模式、模板方法、工厂模式、组合模式

11.7.1 继承设计原则

原则说明建议
组合优于继承继承是强耦合优先使用has-a关系
里氏替换原则子类可替换父类子类不应违反父类契约
接口隔离接口要小而专多个小接口优于一个大接口
依赖倒置依赖抽象而非具体面向接口编程
单一职责类只有一个变化原因避免上帝类

11.7.2 常见陷阱与规避

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 陷阱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 = extra

11.8 练习题

基础题

  1. 创建Vehicle基类,派生Car和Bicycle类,各自实现移动方式描述。

  2. 使用多态实现图形面积计算器,支持矩形、圆形和三角形。

  3. 创建抽象类Shape,要求子类实现area()和perimeter()。

进阶题

  1. 实现LogMixin和TimestampMixin,为任意类添加日志和时间戳功能。

  2. 使用Protocol定义Iterator接口,并实现自定义迭代器。

  3. 实现一个简单的插件系统,使用ABC定义插件接口,支持动态加载。

项目实践

  1. 图形编辑器框架:编写一个程序,要求:
    • 使用ABC定义Shape接口(area、perimeter、draw、resize)
    • 实现Rectangle、Circle、Triangle具体图形
    • 使用Mixin添加Serializable和Comparable功能
    • 使用Protocol定义Renderer接口
    • 支持Canvas类管理多个图形,计算总面积
    • 实现图形的序列化与反序列化

思考题

  1. Python的MRO为什么使用C3线性化?菱形继承中super()是如何工作的?

  2. Mixin模式与普通多继承有什么区别?什么情况下应使用Mixin?

  3. Protocol相比ABC有什么优势?在什么场景下应优先使用Protocol?

11.9 延伸阅读

11.9.1 面向对象设计

  • 《设计模式:可复用面向对象软件的基础》 (GoF) — 23种经典设计模式
  • 《Head First设计模式》 — 设计模式入门经典
  • 《敏捷软件开发:原则、模式与实践》 (Robert C. Martin) — OOP实践指南
  • SOLID原则详解 — 面向对象设计的五大原则

11.9.2 Python继承机制

11.9.3 类型系统

11.9.4 设计模式资源


下一章:第12章 高级面向对象特性