装饰器
装饰器的原理以及函数类型的装饰器在网上有很多描述,本文我就只讲我对于 将装饰器定义为类的理解。
要将装饰器定义为一个类,需要在类中声明__call__
和__get__
方法,例子如下:
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)就是将方法和实例绑定起来,这样在这个实例中就包含了这个方法,就可以顺利调用了。
2:如果在原来的方法中需要使用self,那么在装饰器返回的方法中也要包含self参数,不然就不行