1. 将装饰器定义为类
# 你想使用一个装饰器去包装函数,但是希望返回一个可调用的实例。 你需要让你的装饰器可以同时工作在类定义的内部和外部。
# 为了将装饰器定义成一个实例,你需要确保它实现了 __call__() 和 __get__() 方法。
import types
from functools import wraps
class 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)
@Profiled
def add(x, y):
return x + y
class 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)
5
9
2
<__main__.Spam object at 0x0000020AEEBF9B70> 5
<__main__.Spam object at 0x0000020AEEBF9B70> 1
<__main__.Spam object at 0x0000020AEEBF9B70> 3
3
3. * 装饰器统计函数调用次数
from functools import wraps
def profiled(func):
ncalls = 0
@wraps(func)
def wrapper(*args, **kwargs):
nonlocal ncalls
ncalls += 1
return func(*args, **kwargs)
wrapper.ncalls = lambda: ncalls
return wrapper
@profiled
def add(x, y):
return x + y
print(add(1, 2))
print(add(3, 4))
print(add.ncalls())
3
7
2