Skip to content

第11章 继承与多态

学习目标

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

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

11.1 继承基础

11.1.1 单继承

python
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()与协作式调用

python
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 方法重写与扩展

python
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 多继承

python
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(方法解析顺序)

python
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模式

python
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 多态与鸭子类型

python
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
# 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(抽象基类)

python
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(结构化类型)

python
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 策略模式

python
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 模板方法模式

python
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 工厂模式

python
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 组合模式

python
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运行时约束
接口文档ProtocolIDE支持好
框架设计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()调用问题

python
# 问题:多继承中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 -> A

11.8.2 菱形继承问题

python
# 问题:菱形继承导致基类多次初始化
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 抽象方法未实现

python
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 ** 2

11.8.4 Mixin状态污染

python
# 问题: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_count

11.8.5 Protocol运行时检查

python
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))  # True

11.9 本章小结

11.6.1 结构化子类型(PEP 544)

python
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 类型系统增强

python
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 组合优于继承

python
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 模式匹配与多态

python
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继承与多态的完整体系:

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

11.9.1 继承设计原则

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

11.9.2 常见陷阱与规避

python
# 陷阱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.10 练习题

基础题

  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.11 延伸阅读

11.11.1 面向对象设计

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

11.11.2 Python继承机制

11.11.3 类型系统

11.11.4 设计模式资源


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

Python技术丛书 - 江苏省宿城中等专业学校