本文共 1621 字,大约阅读时间需要 5 分钟。
装饰器的原理以及函数类型的装饰器在网上有很多描述,本文我就只讲我对于 将装饰器定义为类的理解。
要将装饰器定义为一个类,需要在类中声明__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参数,不然就不行
转载于:https://blog.51cto.com/zhengdzy/2137203