You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现感知self状态的Python类方法装饰器以记录元数据

实现train模式下记录操作的DataFormatter类

你遇到的核心问题是类内部装饰器在类定义阶段就会执行,此时还没有创建类实例,自然无法访问self.mode和self.metadata。但你的需求完全可行,只需要把元数据记录的逻辑延迟到方法调用时执行即可。

原代码的问题

  1. __init__方法中没有给self.mode赋值,导致后续无法判断模式
  2. 装饰器meta在类定义时就尝试访问self,但此时实例还不存在
  3. 参数处理逻辑只考虑了位置参数,没有兼容关键字参数

修正后的代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:40:35