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 结构化子类型(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.7 本章小结

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

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

11.7.1 继承设计原则

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

11.7.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.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章 高级面向对象特性

青少年创意编程 - 高中Python组 - 江苏省宿城中等专业学校