装饰器

装饰器的原理以及函数类型的装饰器在网上有很多描述,本文我就只讲我对于 将装饰器定义为类的理解。

要将装饰器定义为一个类,需要在类中声明__call____get__方法,例子如下:

from time import timeclass 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_propertyclass 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)就是将方法和实例绑定起来,这样在这个实例中就包含了这个方法,就可以顺利调用了。

2:如果在原来的方法中需要使用self,那么在装饰器返回的方法中也要包含self参数,不然就不行