如何实现Python类装饰器?将子类方法添加至待处理函数列表
问题描述
想要实现一个Python装饰器,能将函数添加到对应类的函数列表中,后续可对这些函数统一处理。尝试的示例代码存在问题:装饰函数时需要传入子类的cls,但类定义完成前无法直接引用子类,常规包装函数方法无法解决这个矛盾:
class A: # 每个子类都应定义_list @classmethod def decorator(cls, f): # 期望cls是子类B cls._flist.append(f) return f @classmethod def processFunctions(cls): for f in cls._flist: ... class B(A): _flist = [] @B.decorator # 此处不可行,类B尚未定义完成 def foo(self): print("Inside foo")
可行的实现方案
方法1:使用元类(最推荐)
元类可以在类创建的最后阶段介入,遍历类成员并收集目标函数,完美避开类未定义的问题:
class FunctionCollectorMeta(type): def __new__(cls, name, bases, attrs): # 创建类实例 new_class = super().__new__(cls, name, bases, attrs) # 初始化子类的函数列表 new_class._flist = [] # 遍历类属性,筛选带标记的函数 for attr_name, attr_value in attrs.items(): if hasattr(attr_value, '_need_collect'): new_class._flist.append(attr_value) return new_class # 基础类使用自定义元类 class A(metaclass=FunctionCollectorMeta): @classmethod def processFunctions(cls): print(f"处理 {len(cls._flist)} 个函数") for func in cls._flist: print(f"目标函数: {func.__name__}") # 定义标记用的装饰器 def collect(func): func._need_collect = True return func # 子类实现 class B(A): @collect def foo(self): print("Inside foo") @collect def bar(self): print("Inside bar") # 测试调用 B.processFunctions()
运行后输出:
处理 2 个函数 目标函数: foo 目标函数: bar
方法2:类装饰器(无需元类)
如果不想使用元类,可以用类装饰器在类定义完成后统一收集函数:
# 标记函数的装饰器 def collect(func): func._need_collect = True return func class A: @classmethod def processFunctions(cls): print(f"处理 {len(cls._flist)} 个函数") for func in cls._flist: print(f"目标函数: {func.__name__}") # 类装饰器:遍历类成员并收集标记函数 def collect_functions(cls): cls._flist = [] for attr_name, attr_value in cls.__dict__.items(): if hasattr(attr_value, '_need_collect'): cls._flist.append(attr_value) return cls # 子类应用类装饰器 @collect_functions class B(A): @collect def foo(self): print("Inside foo") @collect def bar(self): print("Inside bar") # 测试调用 B.processFunctions()
方法3:延迟绑定装饰器(手动初始化)
这种方法兼容原有的装饰器思路,但需要手动完成函数列表的初始化,适合对原有代码改动较小的场景:
class A: # 用父类存储待绑定的函数 _pending_funcs = [] @classmethod def decorator(cls, func): cls._pending_funcs.append(func) return func @classmethod def processFunctions(cls): print(f"处理 {len(cls._flist)} 个函数") for func in cls._flist: print(f"目标函数: {func.__name__}") # 子类定义 class B(A): _flist = [] @A.decorator def foo(self): print("Inside foo") # 手动将待绑定函数转移到子类列表 B._flist.extend(A._pending_funcs) A._pending_funcs.clear() # 避免影响其他子类 # 测试调用 B.processFunctions()
内容的提问来源于stack exchange,提问作者David Davó
相关产品推荐
相关产品推荐

