同一类中定义并使用装饰器的正确方法
同一类中定义并使用装饰器的正确方法
我来帮你搞定这个类内装饰器的问题~你遇到的错误本质很清晰:在类定义的阶段,实例还没创建出来呢,直接把实例方法write_log当装饰器用,Python根本找不到它需要的self参数,自然就会参数混乱报错。
先拆解下你出错的原因:
你的write_log是个实例方法,第一个参数必须是self,但当你写@write_log("This is a log.")时,Python会立刻执行这个调用——这时候它把字符串"This is a log."当成了self参数,可函数还需要一个log参数没传,所以就报了“缺少log参数”的错误,完全是参数顺序搞混了。
下面给你两种可行的正确写法,都能完美达到你的预期:
方法一:调整装饰器结构,从调用参数中获取实例
这种写法不需要把装饰器绑定到类,直接通过方法调用时的参数拿到self:
from functools import wraps class BaseClass: def __init__(self, id): self.id = id # 装饰器工厂:先接收日志内容 def write_log(log): def decorator(initial_func): # 保留原方法的元信息,避免后续出现奇怪问题 @wraps(initial_func) def wrapper(*args, **kwargs): # 被装饰的是实例方法,第一个参数肯定是self self = args[0] print(f"{self.id}: {log}") return initial_func(*args, **kwargs) return wrapper return decorator @write_log("This is a log.") def my_method(self, some_param): # 要对应你调用时传的参数2 print(f"This is a test.") # 实例化时必须传id参数,和你预期的输出对应传6 test = BaseClass(6) test.my_method(2)
运行这段代码,会精准输出你想要的内容:
6: This is a log. This is a test.
方法二:把装饰器设为静态方法
如果你想让装饰器属于类的一部分,可以把它标记为静态方法,明确它不需要self或类参数:
from functools import wraps class BaseClass: def __init__(self, id): self.id = id @staticmethod def write_log(log): def decorator(initial_func): @wraps(initial_func) def wrapper(*args, **kwargs): self = args[0] print(f"{self.id}: {log}") return initial_func(*args, **kwargs) return wrapper return decorator @write_log("This is a log.") def my_method(self, some_param): print(f"This is a test.") test = BaseClass(6) test.my_method(2)
效果和方法一完全一致,只是把装饰器归到了类的静态方法范畴里。
另外还要修正你原代码里的两个小疏漏:
__init__方法要求传id参数,实例化时不能空着,得写BaseClass(6);my_method要接收你调用时传的2,所以方法定义里必须加一个参数(比如上面的some_param)。
最后说下你尝试加self在装饰器前为什么会失败:比如写@self.write_log(...),但在类定义阶段,self这个变量根本不存在——它只有在实例方法内部才有意义,Python直接会报NameError,完全是合理的报错。
备注:内容来源于stack exchange,提问作者חיים קרופניק
相关产品推荐
相关产品推荐

