装饰器的原理以及函数类型的装饰器在网上有不少描述,本文我就只讲我对于 将装饰器定义为类的理解。app
要将装饰器定义为一个类,须要在类中声明__call__
和__get__
方法,例子以下:ide
from time import time class ttl_property(object): def __init__(self, ttl=None): self.ttl = ttl def __call__(self, func): def wrapper(*args,**kw): if 'name' not in self.__dict__.keys(): self.__dict__['name']=(func(*args,**kw),time()) last=self.__dict__['name'][1] value=self.__dict__['name'][0] now=time() if now-last>self.ttl: value=func(*args,**kw) self.__dict__['name']=(value,now) return value return wrapper def __get__(self, instance, owner): if instance is None: return self else: return types.MethodType(self, instance) def __set__(self, instance, value): self.__dict__['name'] = (value, time())
from ttl_property import ttl_property class Book(object): """ >>> b = Book() >>> b.price 80.0 >>> b.price 80.0 >>> time.sleep(3) >>> b.price 64.0 >>> b.price 64.0 >>> time.sleep(3) >>> b.price 51.2 """ def __init__(self): self._price = 100.0 @ttl_property(ttl=2) def price(self): self._price = self._price * 0.8 return self._price
这是我在一个网站上作的实验,在这个实验中须要定义一个装饰器类ttl_property来装饰Book类中的函数,__call__
函数能够将类的调用和函数相似,具体请查询网上资料。函数
我要着重强调两点:网站
1:装饰器类中的__get__
方法很重要,由于在装饰器中返回的函数并非本来类中的函数,也就是说在本来类所对应的实例中,这个函数并不存在,因此若是没有__get__
方法,那么调用就会出问题;那么types.MethodType(self, instance)就是将方法和实例绑定起来,这样在这个实例中就包含了这个方法,就能够顺利调用了。code
2:若是在原来的方法中须要使用self,那么在装饰器返回的方法中也要包含self参数,否则就不行get