Python 3.10装饰器困惑:如何包装类扩展__init__追踪函数调用
带参数的类装饰器实现方案
核心实现思路
带参数的类装饰器需要采用嵌套函数结构:外层函数接收装饰器的默认参数,内层函数作为真正的类装饰器,负责修改目标类的方法逻辑。同时要保证实例化时传入的参数优先级高于装饰器默认值,且保留原类方法的元信息。
完整代码实现
import functools def keep_track(keep_track=True, do_print=True): def class_decorator(cls): # 保存原类的方法,避免覆盖后丢失逻辑 original_init = cls.__init__ original_call_me = cls.call_me # 包装__init__:添加参数处理逻辑 @functools.wraps(original_init) def new_init(self, *args, **kwargs): # 实例化传参优先,否则用装饰器默认值 self.keep_track = kwargs.pop('keep_track', keep_track) self.do_print = kwargs.pop('do_print', do_print) # 执行原__init__逻辑 original_init(self, *args, **kwargs) # 仅当开启追踪时初始化调用计数 if self.keep_track: self.call_count = 0 # 包装call_me:添加打印、调用记录逻辑 @functools.wraps(original_call_me) def new_call_me(self, *args, **kwargs): if self.do_print: print(f"[打印] call_me调用参数: {args}, {kwargs}") if self.keep_track: self.call_count += 1 print(f"[记录] 第 {self.call_count} 次调用call_me") # 执行原call_me逻辑 return original_call_me(self, *args, **kwargs) # 替换类中的方法 cls.__init__ = new_init cls.call_me = new_call_me return cls return class_decorator # 测试用的目标类 @keep_track(do_print=False) # 装饰器默认关闭打印 class Foo: def __init__(self, name): self.name = name print(f"Foo实例初始化: name={self.name}") def call_me(self, message): print(f"原方法逻辑: {message}") # 验证功能 if __name__ == "__main__": # 实例1:使用装饰器默认参数 foo1 = Foo("Alice") foo1.call_me("Hello") foo1.call_me("Hi") print(f"foo1调用次数: {foo1.call_count}\n") # 实例2:实例化时覆盖装饰器参数 foo2 = Foo("Bob", do_print=True, keep_track=False) foo2.call_me("Hello Bob") try: print(f"foo2调用次数: {foo2.call_count}") except AttributeError: print("foo2未开启调用记录")
关键细节说明
- 参数优先级处理:通过
kwargs.pop从实例化参数中提取keep_track/do_print,优先使用实例化传参,否则 fallback 到装饰器默认值,避免干扰原__init__的参数逻辑。 - 元信息保留:用
functools.wraps包装新方法,确保原方法的__name__、__doc__等元信息不丢失,避免破坏类的原有结构。 - 条件初始化:仅当
keep_track=True时才创建call_count属性,避免给不需要追踪的实例添加冗余属性。
你之前可能踩的坑
- 未使用嵌套函数结构:带参数的装饰器必须先接收参数,再返回真正的装饰器函数,直接写单层装饰器会导致参数传递逻辑混乱。
- 未保存原方法:直接替换类方法会丢失原逻辑,必须先保存原方法引用,再在新方法中调用。
- 参数处理错误:实例化传参未从
kwargs中取出,导致原__init__接收到多余参数报错。
内容的提问来源于stack exchange,提问作者SumNeuron
相关产品推荐
相关产品推荐

