2010-06-23 54 views
3

我一直在尋找在Python一些延遲加載屬性的裝飾和整個這個例子(http://code.activestate.com/recipes/363602-lazy-property-evaluation/)發生了:這個Python裝飾器是如何工作的?

class Lazy(object): 
    def __init__(self, calculate_function): 
     self._calculate = calculate_function 

    def __get__(self, obj, _=None): 
     if obj is None: 
      return self 
     value = self._calculate(obj) 
     setattr(obj, self._calculate.func_name, value) 
     return value 

# Sample use: 

class SomeClass(object): 

    @Lazy 
    def someprop(self): 
     print 'Actually calculating value' 
     return 13 

o = SomeClass() 
o.someprop 
o.someprop 

我的問題是,如何工作的呢?我對裝飾器的理解是它們必須是可調用的(因此可以是實現__call__的函數或調用),但Lazy顯然不是,如果我嘗試Lazy(someFunc)(),它會引發異常,如預期的那樣。我錯過了什麼?

回答

8

SomeClass類的實例o被訪問名爲someprop的屬性,如果SomeClass包含描述命名o,那麼就使用該描述符的類的__get__方法。有關描述符的更多信息,請參閱this guide。不要讓Lazy在這裏作爲裝飾器在句法上被使用,因爲Lazy本身有一個__get__方法,因此您無法看到它的實例是描述符。

的修飾語法

@Lazy 
    def someprop(self): 
     ... 

也沒有了,不能少,比語法糖爲:

def someprop(self): 
     ... 
    someprop = Lazy(someprop) 

當它與修飾語法或直接用在Lazy約束條件是沒有不同:它必須接受someprop(一個函數)作爲它的參數 - 不管它返回什麼。在這裏,Lazy是一個類,因此它返回自己的一個實例,並且有一個特殊的方法,以便實例是一個描述符(因此,在SomeClass類的o實例上訪問someprop屬性時調用該方法) - 這就是全部這就是它,不多也不少。