# 把装饰器定义为类
# 定义中需要实现__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):
re
4.1 在类中定义装饰器
以实例或者以类方法的形式进行应用
代码解析:
from functools importwrapsclassA:#Decorator as an instance method
defdecorator1(self, func):
@wraps(func)def wrapper(*args, **kwargs):print('Decorator 1')return func(*args, **kwargs)returnwrapper#Decorator as a class method
@classmethoddefdecorator2(cls, func):
@wraps(func)def wrapper(*args, **kwargs):print('Decorator 2')return func(*args, **kwargs)returnwrapper#As an instance method
a =A()
@a.decorator1defspam():pass
#As a class method
@A.decorator2defgrok():pass
#这种方法在标准库中就有示例,比如说@property,实际是拥有#getter()/setter()/deleter()方法的类,类中每一个定义的方#法可以作为装饰器#比如代码如下:
classPerson:#Create a property instance
first_name =property()#Apply decorator methods
@first_name.getterdeffirst_name(self):returnself._first_name
@first_name.setterdeffirst_name(self, value):if notisinstance(value, str):raise TypeError('Expected a string')
self._first_name= value
4.2 把装饰器定义为类
定义中需要实现__call__(),__get__() 方法
#把装饰器定义为类#定义中需要实现__call__(),__get__() 方法
importtypesfrom functools importwrapsclassProfiled:def __init__(self, func):
wraps(func)(self)
self.ncalls=0def __call__(self, *args, **kwargs):
self.ncalls+= 1
return self.__wrapped__(*args, **kwargs)def __get__(self, instance, cls):if instance isNone:returnselfelse:returntypes.MethodType(self, instance)#在类外使用装饰器
@Profileddefadd(x, y):return x +y#在类中使用装饰器
classSpam:
@Profileddefbar(self, x):print(self, x)print(add(2, 3)) #5
print(add(3, 3)) #6
print(add(4, 3)) #7
print(add.ncalls) #3
s=Spam()print(s.bar(1)) #<__main__.Spam object at 0x000001F39D74D4E0> 1
print(s.bar(2)) #<__main__.Spam object at 0x000001F39D74D4E0> 2
print(s.bar(3)) #<__main__.Spam object at 0x000001F39D74D4E0> 3
print(Spam.bar.ncalls) #3
print(s.bar.ncalls) #3