课程 21:类的进阶

课程目录

1. 继承、super()与MRO

1.1 多层继承与super()

class Animal:  # 基类:动物
    def speak(self):
        print('动物叫')

class Mammal(Animal):  # 子类:哺乳动物,继承自Animal
    def speak(self):  # 重写父类方法
        print('哺乳动物叫')

class Dog(Mammal):  # 子类:狗,继承自Mammal
    def speak(self):  # 重写父类方法
        super().speak()  # 调用父类(Mammal)的speak方法
        print('狗叫')  # 添加狗特有的行为

# 创建Dog对象并测试多层继承
d = Dog()
d.speak()  # 输出:哺乳动物叫 狗叫

1.2 MRO与多重继承

class A: pass  # 基类A
class B(A): pass  # 类B继承自A
class C(A): pass  # 类C继承自A
class D(B, C): pass  # 类D多重继承自B和C

# 查看方法解析顺序(MRO)
print(D.__mro__)  # 显示D类的继承顺序:(D, B, C, A, object)
方法解析顺序(MRO): 决定多重继承下方法的查找顺序。super()遵循MRO。

1.3 组合与继承对比

class Engine:  # 发动机类
    def start(self):
        print('发动机启动')

class Car:  # 汽车类
    def __init__(self):
        self.engine = Engine()  # 组合:汽车包含发动机对象
    
    def drive(self):
        self.engine.start()  # 通过组合对象调用方法
        print('汽车行驶')

# 创建汽车对象并测试组合
car = Car()
car.drive()  # 输出:发动机启动 汽车行驶
建议: 组合优于继承,优先用组合实现“有一个”,继承实现“是一个”。

2. 多态、鸭子类型与抽象基类

2.1 多态与鸭子类型

class Cat:  # 猫类,也有speak方法
    def speak(self):
        print('喵喵!')

def animal_speak(animal):  # 多态函数:接受任何有speak方法的对象
    animal.speak()  # 调用对象的speak方法

# 多态演示:不同对象调用相同接口,产生不同结果
for a in [Dog(), Cat()]:  # 创建不同类型的对象
    animal_speak(a)  # 多态:同一函数处理不同类型对象

2.2 抽象基类与接口设计

from abc import ABC, abstractmethod  # 导入抽象基类相关模块

class Shape(ABC):  # 抽象基类:定义接口
    @abstractmethod  # 抽象方法装饰器
    def area(self):  # 抽象方法:子类必须实现
        pass

class Rectangle(Shape):  # 具体实现类:继承抽象基类
    def __init__(self, w, h):
        self.w = w  # 宽度
        self.h = h  # 高度
    
    def area(self):  # 实现抽象方法
        return self.w * self.h

# 抽象基类不能直接实例化
# s = Shape()  # TypeError: Can't instantiate abstract class
接口设计: 用抽象基类强制子类实现接口,便于统一和扩展。

2.3 类型检查与isinstance

# 类型检查:判断对象是否属于某个类或其子类
print(isinstance(Rectangle(1,2), Shape))  # True:Rectangle是Shape的子类

3. 类方法、静态方法与设计模式

3.1 工厂方法与单例模式

class Account:  # 账户类
    def __init__(self, owner):
        self.owner = owner  # 账户持有人
    
    @classmethod  # 类方法装饰器
    def create(cls, owner):  # 工厂方法:用于创建对象
        return cls(owner)  # 返回新创建的实例

class Singleton:  # 单例模式类
    _instance = None  # 类变量:存储唯一实例
    
    def __new__(cls, *args, **kwargs):  # 重写__new__方法
        if not cls._instance:  # 如果还没有实例
            cls._instance = super().__new__(cls)  # 创建新实例
        return cls._instance  # 返回唯一实例

3.2 静态方法实际应用

class Math:  # 数学工具类
    @staticmethod  # 静态方法装饰器
    def add(a, b):  # 静态方法:不需要self或cls参数
        return a + b

# 通过类名调用静态方法
print(Math.add(3, 5))  # 输出:8
实际应用: 工厂方法用于批量创建对象,单例模式保证全局唯一实例。

4. 魔法方法与容器协议

4.1 常用魔法方法与协议

class MyList:  # 自定义列表类
    def __init__(self):
        self.data = []  # 内部数据存储
    
    def __getitem__(self, idx):  # 支持下标访问:obj[index]
        return self.data[idx]
    
    def __setitem__(self, idx, value):  # 支持下标赋值:obj[index] = value
        self.data[idx] = value
    
    def __len__(self):  # 支持len()函数
        return len(self.data)
    
    def __iter__(self):  # 支持for循环遍历
        return iter(self.data)
    
    def __contains__(self, item):  # 支持in操作符
        return item in self.data
    
    def append(self, value):  # 添加元素方法
        self.data.append(value)

# 测试自定义容器
lst = MyList()
lst.append(10)  # 添加元素
lst.append(20)
print(lst[0], len(lst), 10 in lst)  # 测试下标访问、长度、成员检查
for x in lst:  # 测试for循环
    print(x)

4.2 只读容器与缓存

class ReadOnlyList:  # 只读列表类
    def __init__(self, data):
        self._data = list(data)  # 私有数据,不允许修改
    
    def __getitem__(self, idx):  # 支持读取
        return self._data[idx]
    
    def __len__(self):  # 支持长度查询
        return len(self._data)
    
    def __setitem__(self, idx, value):  # 禁止修改
        raise TypeError('只读容器不允许修改')

# 测试只读容器
rol = ReadOnlyList([1,2,3])
print(rol[0], len(rol))  # 可以读取:1 3
# rol[0] = 10  # TypeError:不允许修改

4.3 生成器与for循环协议

class Fib:  # 斐波那契数列迭代器
    def __init__(self, n):
        self.n = n  # 生成n个斐波那契数
    
    def __iter__(self):  # 返回迭代器对象
        self.a, self.b, self.count = 0, 1, 0  # 初始化斐波那契数列
        return self
    
    def __next__(self):  # 返回下一个值
        if self.count < self.n:  # 如果还有更多数字
            val = self.a  # 当前值
            self.a, self.b = self.b, self.a + self.b  # 更新斐波那契数列
            self.count += 1  # 计数器加1
            return val  # 返回当前值
        else:
            raise StopIteration  # 迭代结束

# 测试斐波那契迭代器
for x in Fib(5):  # 生成前5个斐波那契数
    print(x)  # 输出:0 1 1 2 3
协议: 容器协议(__getitem__、__len__、__contains__),迭代器协议(__iter__、__next__)。

5. 实际应用案例

5.1 插件系统与扩展

class PluginBase(ABC):  # 插件基类:定义插件接口
    @abstractmethod
    def run(self): pass  # 抽象方法:所有插件必须实现

class PluginA(PluginBase):  # 插件A:具体实现
    def run(self): 
        print('A插件')

class PluginB(PluginBase):  # 插件B:具体实现
    def run(self): 
        print('B插件')

# 插件系统:统一管理多个插件
plugins = [PluginA(), PluginB()]
for p in plugins:  # 遍历所有插件
    p.run()  # 调用插件的run方法

5.2 LRU缓存容器

from collections import OrderedDict  # 导入有序字典

class LRUCache:  # LRU(最近最少使用)缓存类
    def __init__(self, capacity):
        self.cache = OrderedDict()  # 用有序字典存储缓存
        self.capacity = capacity  # 缓存容量
    
    def get(self, key):  # 获取缓存值
        if key in self.cache:  # 如果键存在
            self.cache.move_to_end(key)  # 移到末尾(标记为最近使用)
            return self.cache[key]  # 返回值
        return -1  # 键不存在返回-1
    
    def put(self, key, value):  # 设置缓存值
        self.cache[key] = value  # 设置值
        self.cache.move_to_end(key)  # 移到末尾(标记为最近使用)
        if len(self.cache) > self.capacity:  # 如果超过容量
            self.cache.popitem(last=False)  # 删除最久未使用的项

# 测试LRU缓存
lru = LRUCache(2)  # 创建容量为2的缓存
lru.put('a', 1)  # 添加键值对
lru.put('b', 2)
lru.get('a')  # 访问'a',使其变为最近使用
lru.put('c', 3)  # 添加'c','b'被淘汰
print(list(lru.cache.items()))  # 输出:[('a', 1), ('c', 3)]
实际应用: 插件系统、缓存、ORM、数据结构等都大量用到OOP进阶特性。
学习建议:OOP进阶特性是写好大型项目的关键,建议多动手实践,理解继承、多态、魔法方法、容器协议、抽象基类、设计模式等高级用法,遇到报错要学会调试和查文档。推荐多用MRO、__repr__、UML等工具辅助调试和设计。
思考题:多态和鸭子类型的区别?自定义容器类有哪些协议?如何设计一个可扩展的插件系统?OOP设计模式在实际开发中的作用?组合和继承如何选择?UML类图在设计中的作用?