裝飾器的原理以及函數類型的裝飾器在網上有不少描述,本文我就只講我對於 將裝飾器定義爲類的理解。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