如何实现感知self状态的Python类方法装饰器以记录元数据
实现train模式下记录操作的DataFormatter类
你遇到的核心问题是类内部装饰器在类定义阶段就会执行,此时还没有创建类实例,自然无法访问self.mode和self.metadata。但你的需求完全可行,只需要把元数据记录的逻辑延迟到方法调用时执行即可。
原代码的问题
__init__方法中没有给self.mode赋值,导致后续无法判断模式- 装饰器
meta在类定义时就尝试访问self,但此时实例还不存在 - 参数处理逻辑只考虑了位置参数,没有兼容关键字参数
修正后的代码
import inspect from functools import wraps import pandas as pd class DataFormatter: def __init__(self, mode, data=None): self.mode = mode # 补上mode的赋值 self.data = data self.metadata = [] def meta(self, f): @wraps(f) def wrapper(*args, **kwargs): # 先执行原方法逻辑 result = f(*args, **kwargs) # 仅在train模式下记录元数据 if self.mode == 'train': # 获取方法的参数签名,跳过第一个self参数 sig = inspect.signature(f) param_names = list(sig.parameters.keys())[1:] # 合并位置参数和关键字参数 param_values = dict(zip(param_names, args)) param_values.update(kwargs) # 存入metadata self.metadata.append({f.__name__: param_values}) return result return wrapper @meta def drop(self, cols): self.data = self.data.drop(cols, axis=1) # 明确axis=1避免歧义 # 可以扩展其他数据处理方法 @meta def fillna(self, value): self.data = self.data.fillna(value)
测试验证
# 模拟训练数据 train_data = pd.DataFrame({ 'col1': [1, 2, None], 'col5': [7, 8, 9], 'col3': [10, 11, 12] }) # train模式下执行操作 formatter = DataFormatter('train', train_data) formatter.drop(['col1', 'col5']) formatter.fillna(0) # 查看记录的元数据 print(formatter.metadata) # 输出:[{'drop': {'cols': ['col1', 'col5']}}, {'fillna': {'value': 0}}]
Infer模式复用操作
# 模拟推理数据 infer_data = pd.DataFrame({ 'col1': [None, 5], 'col5': [13, 14], 'col3': [15, None] }) infer_formatter = DataFormatter('infer', infer_data) # 按顺序执行train阶段记录的操作 for op in formatter.metadata: method_name, params = next(iter(op.items())) getattr(infer_formatter, method_name)(**params) print(infer_formatter.data) # 输出: # col3 # 0 15.0 # 1 0.0
关键说明
- 使用
functools.wraps保留原方法的名称和元信息,避免调试时出现混淆 - 用
inspect.signature更可靠地解析参数,兼容位置参数和关键字参数 - 元数据记录逻辑放在wrapper内部,只有当实例调用方法时才会执行,此时
self已经存在
内容的提问来源于stack exchange,提问作者Damian Satterthwaite-Phillips
相关产品推荐
相关产品推荐

