如何编写Python装饰器实现多类下载方法的通用文件缓存逻辑
你当前设计的装饰器需要在绑定到方法时就传入filepath和use_cache参数,但filepath是类实例化后才会生成的实例属性,use_cache是调用download方法时才传入的动态参数,二者都无法在定义方法阶段提前传入装饰器,所以这个思路不可行。
以下是两种可行的通用解决方案:
方案1:适配实例方法的装饰器
利用实例方法第一个参数是self的特性,在装饰器内部直接获取实例的filepath属性,以及调用时传入的use_cache参数,不需要提前传参:
from functools import wraps from pathlib import Path def download_cache(func): @wraps(func) def wrapper(self, use_cache=True, *args, **kwargs): # 通用缓存逻辑 if use_cache and self.filepath.exists(): return self.filepath # 执行子类自定义的下载逻辑 func(self, use_cache=use_cache, *args, **kwargs) return self.filepath return wrapper
使用方式非常简单,只需要给每个类的download方法加上装饰器,方法内部只保留差异化的下载代码即可:
class Data(object): def __init__(self): self.filepath = Path("filepath") @download_cache def download(self, use_cache=True): # 仅保留差异化的下载实现 print(f"downloading to {self.filepath}")
方案2:基类继承(更适合流水线多类场景)
如果你的所有数据类都是流水线内的同类型组件,用抽象基类统一收敛公共逻辑会更易维护,后续要调整缓存规则、增加重试/日志等公共能力只需要修改基类即可:
from pathlib import Path from abc import ABC, abstractmethod class BaseDownloadableData(ABC): # 约定所有子类必须定义filepath属性 filepath: Path def download(self, use_cache=True): # 全局统一缓存逻辑 if use_cache and self.filepath.exists(): return self.filepath # 调用子类实现的专属下载逻辑 self._download_logic() return self.filepath @abstractmethod def _download_logic(self): """子类实现具体的下载逻辑,不需要处理缓存判断""" pass
子类只需要继承基类,实现下载逻辑即可:
class CustomData(BaseDownloadableData): def __init__(self): self.filepath = Path("custom_filepath") def _download_logic(self): # 仅写差异化的下载代码 print(f"downloading custom data to {self.filepath}")
方案选择建议
- 如果只是给零散的几个类加缓存能力,选择装饰器更灵活,不需要修改类的继承关系
- 如果是同一条流水线内的多个数据类统一规范,选择基类继承可维护性更高
内容的提问来源于stack exchange,提问作者turnerm
相关产品推荐
相关产品推荐

