1. 将装饰器定义为类
# 你想使用一个装饰器去包装函数,但是希望返回一个可调用的实例。 你需要让你的装饰器可以同时工作在类定义的内部和外部。# 为了将装饰器定义成一个实例,你需要确保它实现了 __call__() 和 __get__() 方法。import typesfrom functools import wrapsclass Profiled: def __init__(self, func): wraps(func)(self) self.ncalls = 0 def __call__(self, *args, **kwargs): self.ncalls += 1 return self.__wrapped__(*args, **kwargs) def __get__(self, instance, cls): if instance is None: return self else: return types.MethodType(self, instance)@Profileddef add(x, y): return x + yclass Spam: @Profiled def bar(self, x): print(self, x)print(add(2, 3))print(add(4, 5))print(add.ncalls)s = Spam()s.bar(5)s.bar(1)s.bar(3)print(Spam.bar.ncalls)
592<__main__.Spam object at 0x0000020AEEBF9B70> 5<__main__.Spam object at 0x0000020AEEBF9B70> 1<__main__.Spam object at 0x0000020AEEBF9B70> 33
3. * 装饰器统计函数调用次数
from functools import wrapsdef profiled(func): ncalls = 0 @wraps(func) def wrapper(*args, **kwargs): nonlocal ncalls ncalls += 1 return func(*args, **kwargs) wrapper.ncalls = lambda: ncalls return wrapper@profileddef add(x, y): return x + yprint(add(1, 2))print(add(3, 4))print(add.ncalls())
372