课程 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类图在设计中的作用?