Python中如何为类的不同实例创建独立的装饰器类实例?
问题解答
这个需求完全可以实现。
问题根因
你当前的写法存在两个核心问题:
- 类装饰器装饰类内方法时,装饰动作在
waiter类定义阶段就完成了,全局只会生成1个decorater实例,所有waiter类的实例共享这一个装饰器实例,所以调用计数是全局累加的,无法按实例独立统计。 - 实例方法
wait_for没有声明self参数,属于语法不规范,当前能跑通是因为装饰器在调用原方法时没有传入实例本身,属于巧合运行。
解决方案
我们可以让装饰器类实现Python的描述符协议,在方法绑定到实例时,为每个实例单独生成一个装饰器实例,把计数存在各自的装饰器实例中即可。
from functools import update_wrapper import time class decorater(): """ counts the number of calls and passes it into function """ def __init__(self, func): self.func = func update_wrapper(self, func) def __get__(self, instance, owner): # 方法绑定到实例时,为当前实例生成专属的装饰器实例 if instance is None: return self bound_decorator = decorater(self.func.__get__(instance, owner)) # 把装饰器实例存到实例属性上,避免重复生成 setattr(instance, self.func.__name__, bound_decorator) return bound_decorator def __call__(self, *args, **kwargs): if not hasattr(self, 'num_calls'): self.num_calls = 0 self.num_calls += 1 # 直接调用绑定后的方法,不需要额外传实例 result = self.func(self.num_calls, *args, **kwargs) print(f"total runs of {self.func.__name__}: {self.num_calls}") return result class waiter(): """ waits for the number of seconds passed in """ @decorater def wait_for(self, seconds, var_name): time.sleep(seconds) print(f"{var_name} waited for {seconds} seconds") waiter1 = waiter() waiter2 = waiter() waiter1.wait_for("waiter1") waiter2.wait_for("waiter2")
运行结果
waiter1 waited for 1 seconds total runs of wait_for: 1 waiter2 waited for 1 seconds total runs of wait_for: 1
完全符合期望输出。
内容的提问来源于stack exchange,提问作者NoHeinz
相关产品推荐
相关产品推荐

