2012-01-23 42 views

回答

7

讓我們來看看一些方法Django的django.db.models.query.QuerySet類:

class QuerySet(object): 
    """ 
    Represents a lazy database lookup for a set of objects. 
    """ 
    def __init__(self, model=None, query=None, using=None): 
     ... 
     self._result_cache = None 
     ... 

    def __len__(self): 
     if self._result_cache is None: 
      ... 
     elif self._iter: 
      ... 
     return len(self._result_cache) 

    def __iter__(self): 
     if self._result_cache is None: 
      ... 
     if self._iter: 
      ... 
     return iter(self._result_cache) 

    def __nonzero__(self): 
     if self._result_cache is not None: 
      ... 

    def __contains__(self, val): 
     if self._result_cache is not None: 
      ... 
     else: 
      ... 
     ... 

    def __getitem__(self, k): 
     ... 
     if self._result_cache is not None: 
     ... 
     ... 

,這些方法遵循的是,沒有查詢到一些真正需要返回一些結果被稱爲方法執行的模式。此時,結果將存儲在self._result_cache中,並且對同一方法的任何後續調用都會返回緩存的值。

+1

原力爲你服務。 – jsbueno

+0

謝謝!我懶得去挖掘周圍的github :) – zsquare

1

不確定哪個庫你在說什麼,但是,從算法的角度來看,我一直使用的細節/ undertsood,如下所示:(僞從一個python新手碼)

class Object: 

    #... Other stuff ... 

    _actual_property = None; 

    def interface(): 
     if _actual_property is None: 
      # Execute query and load up _actual_property 

     return _actual_property 

主要是因爲界面和實現是分開的,你可以根據請求定義要執行的行爲。

+0

小雞蛋裏挑骨頭:如果延遲評估計算返回None,這將在每次調用interface()時重新評估查詢。 –

+0

假設評估可能(或可能)返回「無」,我相信這很明顯,我只是試圖提出這個概念......而不是生產代碼。 – jondavidjohn

+0

問題是關於Python的透明方法來做到這一點 – jsbueno

1

的機制是相當簡單:

class Lazy: 
    def __init__(self, evaluate): 
     self.evaluate = evaluate 
     self.computed = False 
    def getresult(self): 
     if not self.computed: 
      self.result = self.evaluate() 
      self.computed = True 
     return self.result 

然後,該實用程序可作爲:

def some_computation(a, b): 
    return ... 

# bind the computation to its operands, but don't evaluate it yet. 
lazy = Lazy(lambda: some_computation(1, 2)) 

# "some_computation()" is evaluated now. 
print lazy.getresult() 

# use the cached result again without re-computing. 
print lazy.getresult() 

此實現使用可調用來表示的計算,但也有關於這一主題的許多變化(例如,要求你實施evaluate()方法的基類等)。

5

在Python中,一個對象可能「存在」 - 但其內在值只有在與其中一個操作符一起使用時才由ouyter世界知道 - 因爲操作符是在類中由魔法名稱定義的用雙下劃線表示,如果一個類在調用操作符時寫入適當的代碼來執行延期代碼,那就好了。

這意味着,如果對象的值例如像字符串一樣使用,那麼使用該對象的porgram的任何部分都會在某個時刻調用「__str__」強制方法。

例如,讓我們創建一個行爲類似於字符串但告訴當前時間的對象。字符串可以連接到其他字符串(__ add__),可以有其長度請求(__len__),等等。如果我們希望它完全適合於他放置一個字符串,那麼必須覆蓋所有方法。這個想法是在調用其中一個操作符時檢索實際值 - 否則,可以將實際對象自由分配給變量並傳遞。需要它的值時

那麼它只會進行評估,人們可以有一些像這樣的代碼:

,並用它在控制檯上,你可以有:

>>> a = timestr() 
>>> b = timestr() 
>>> print b 
17:16:22 
>>> print a 
17:16:25 

如果您希望懶惰評估的值是您的對象的屬性(如Peson.name),而不是您的對象的實際行爲 - 它更容易。因爲Python允許所有的對象屬性都是一種特殊的類型 - 稱爲描述符 - 實際上每次訪問屬性時都會調用一個方法。因此,只需創建一個名爲__get__的適當方法來實現真正的值。只有在需要屬性時纔會調用此方法。

的Python甚至有一個方便的描述符創建一個工具 - 「屬性」關鍵字,使這個更容易 - 你傳遞的是代碼生成的屬性作爲第一個參數性能的方法。

所以,有一個事件類與懶惰(和生活)進行評估的時候,只是一個書面方式的事情:

import time 

class Event(object): 
    @property 
    def time(self): 
     timet = time.localtime() 
     return " %s:%s:%s " % (timet.tm_hour, timet.tm_min, timet.tm_sec) 

而且使用它作爲:

>>> e= Event() 
>>> e.time 
' 17:25:8 ' 
>>> e.time 
' 17:25:10 ' 
+0

非常感謝詳細的解釋。我把另一個作爲答案的唯一原因是因爲海報引用了我問到的實際圖書館。 – zsquare