首页 / 知识库 / 0基础入门-阅读资料 / 0基础-python入门到精通

第 12 章 继承与多态

12.1 单继承与方法重写

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        return f"{self.name} makes a sound"
    
    def __repr__(self):
        return f"{type(self).__name__}({self.name!r})"

class Dog(Animal):
    def speak(self):     # 重写(override)父类方法
        return f"{self.name} says: Woof!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says: Meow!"
    
    def purr(self):      # 子类独有的方法
        return f"{self.name} purrs..."

dog = Dog("Buddy")
cat = Cat("Whiskers")

print(dog.speak())    # Buddy says: Woof!
print(cat.speak())    # Whiskers says: Meow!
print(cat.purr())     # Whiskers purrs...

# isinstance 和 issubclass
print(isinstance(dog, Dog))      # True
print(isinstance(dog, Animal))   # True — Dog 是 Animal 的子类
print(issubclass(Dog, Animal))   # True

12.2 super() 的正确用法

super() 用于调用父类(或 MRO 中的下一个类)的方法:

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # 调用父类的 __init__
        self.breed = breed

dog = Dog("Buddy", 3, "Labrador")
print(dog.name, dog.age, dog.breed)

super() 在多继承中的行为

super() 不是”调用父类”,而是”调用 MRO 中的下一个类”:

class A:
    def method(self):
        print("A.method")

class B(A):
    def method(self):
        print("B.method")
        super().method()   # 调用 MRO 中下一个,不一定是 A

class C(A):
    def method(self):
        print("C.method")
        super().method()

class D(B, C):
    def method(self):
        print("D.method")
        super().method()

D().method()
# D.method
# B.method
# C.method    ← B 的 super() 调用的是 C,不是 A!
# A.method

print(D.__mro__)
# (D, B, C, A, object)

协作式多继承

正确使用 super() 实现协作式多继承:

class Base:
    def __init__(self, **kwargs):
        # 吞掉所有剩余参数,终止 super() 链
        pass

class Name(Base):
    def __init__(self, name, **kwargs):
        super().__init__(**kwargs)
        self.name = name

class Age(Base):
    def __init__(self, age, **kwargs):
        super().__init__(**kwargs)
        self.age = age

class Person(Name, Age):
    pass

p = Person(name="Alice", age=30)
print(p.name, p.age)  # Alice 30

12.3 多继承与 MRO(C3 线性化)

Python 支持多继承,方法查找顺序由 MRO(Method Resolution Order) 决定:

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

# MRO: D → B → C → A → object
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)

# 也可以用 mro() 方法
print(D.mro())

C3 线性化算法

MRO 使用 C3 线性化算法,保证:

  1. 子类在父类之前
  2. 多个父类的相对顺序保持不变
  3. 如果无法满足以上规则,抛出 TypeError
# 菱形继承问题
#       A
#      / \
#     B   C
#      \ /
#       D

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):
    pass

D().method()  # B — 按 MRO 顺序,B 在 C 前面

# 不合法的继承结构会报错
# class X(A, B): pass  # 如果 MRO 无法线性化,会 TypeError

12.4 Mixin 设计模式

Mixin 是一种不独立使用、专门用来”混入”其他类的小型类:

class JsonMixin:
    """提供 JSON 序列化能力"""
    def to_json(self):
        import json
        return json.dumps(self.__dict__, ensure_ascii=False)
    
    @classmethod
    def from_json(cls, json_str):
        import json
        data = json.loads(json_str)
        return cls(**data)

class ReprMixin:
    """提供友好的字符串表示"""
    def __repr__(self):
        attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items())
        return f"{type(self).__name__}({attrs})"

class ValidateMixin:
    """提供数据验证能力"""
    def validate(self):
        for attr, rules in getattr(self, '_validators', {}).items():
            value = getattr(self, attr)
            for rule in rules:
                rule(attr, value)

# 通过多继承混入多种能力
class User(JsonMixin, ReprMixin):
    def __init__(self, name, age):
        self.name = name
        self.age = age

user = User("Alice", 30)
print(user)              # User(name='Alice', age=30)
print(user.to_json())    # {"name": "Alice", "age": 30}

user2 = User.from_json('{"name": "Bob", "age": 25}')
print(user2)             # User(name='Bob', age=25)

Mixin 的原则

  • Mixin 不应该有 __init__(或尽量简单)
  • Mixin 应该只提供一组相关的方法
  • 命名以 Mixin 结尾,表明意图
  • 放在继承列表的前面(MRO 优先)

12.5 抽象基类 ABC 与 @abstractmethod

抽象基类定义接口,强制子类实现特定方法:

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self) -> float:
        """计算面积"""
        ...
    
    @abstractmethod
    def perimeter(self) -> float:
        """计算周长"""
        ...
    
    def description(self):
        """非抽象方法,子类可选重写"""
        return f"{type(self).__name__}: area={self.area():.2f}"

# 不能实例化抽象类
# Shape()  # TypeError: Can't instantiate abstract class Shape

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14159 * self.radius ** 2
    
    def perimeter(self):
        return 2 * 3.14159 * self.radius

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height
    
    def perimeter(self):
        return 2 * (self.width + self.height)

# 如果忘了实现抽象方法,实例化时会报错
# class Incomplete(Shape):
#     def area(self):
#         return 0
# Incomplete()  # TypeError: Can't instantiate... perimeter

# 多态使用
shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
    print(shape.description())
# Circle: area=78.54
# Rectangle: area=12.00

抽象属性

from abc import ABC, abstractmethod

class Vehicle(ABC):
    @property
    @abstractmethod
    def max_speed(self) -> float:
        ...
    
    @abstractmethod
    def fuel_type(self) -> str:
        ...

class Car(Vehicle):
    @property
    def max_speed(self):
        return 200.0
    
    def fuel_type(self):
        return "gasoline"

12.6 鸭子类型与协议(Protocol)

“如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。”

Python 不关心对象的类型,只关心它有没有需要的方法:

class Duck:
    def quack(self):
        return "Quack!"
    def walk(self):
        return "Walking like a duck"

class Person:
    def quack(self):
        return "I'm quacking like a duck!"
    def walk(self):
        return "I'm walking like a duck!"

class Robot:
    def quack(self):
        return "Beep boop quack"
    def walk(self):
        return "Mechanical walking"

def duck_test(thing):
    # 不检查类型,只要有 quack 和 walk 方法就行
    print(thing.quack())
    print(thing.walk())

# 所有对象都能通过"鸭子测试"
duck_test(Duck())
duck_test(Person())
duck_test(Robot())

协议(Protocol)— 结构化子类型(Python 3.8+)

Protocol 是鸭子类型的形式化——定义结构化接口,无需继承:

from typing import Protocol

class Drawable(Protocol):
    def draw(self) -> str:
        ...

class Circle:
    def draw(self) -> str:
        return "Drawing a circle"

class Square:
    def draw(self) -> str:
        return "Drawing a square"

def render(shape: Drawable) -> None:
    print(shape.draw())

# Circle 和 Square 没有继承 Drawable,但符合其"结构"
render(Circle())   # Drawing a circle — 类型检查通过
render(Square())   # Drawing a square — 类型检查通过

ABC vs Protocol

ABCProtocol
需要继承
运行时检查isinstance() 可用默认不可用(需 runtime_checkable
适用场景明确的类层级鸭子类型、第三方类
哲学名义类型(Nominal)结构类型(Structural)
from typing import Protocol, runtime_checkable

@runtime_checkable
class Sized(Protocol):
    def __len__(self) -> int:
        ...

# 支持 isinstance 检查
print(isinstance([1, 2, 3], Sized))   # True — list 有 __len__
print(isinstance("hello", Sized))      # True — str 有 __len__
print(isinstance(42, Sized))           # False — int 没有 __len__

本章小结:Python 的继承体系以 MRO 和 C3 线性化为基础,通过 super() 实现协作式多继承。Mixin 是多继承的最佳实践,ABC 提供了形式化的接口约束。但 Python 的核心哲学是鸭子类型——关注行为而非身份,Protocol 将这一哲学与类型系统优雅结合。