2012-01-23 6 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 

基本的理由インタフェースと実装が分離されている場合、要求に応じて実行する動作を定義できます。

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 

そして、このユーティリティは以下のように使用することができる:

+0

小nitpickます。if lazilyに評価された計算によって 'None'が返されたとき、' interface() 'が呼び出されるたびにクエリが再評価されます。 –

+0

これは、評価が「なし」を返す可能性があると仮定しているため、私は単にプロダクションコードではなくコンセプトを提示しようとしていることは明らかです。 – jondavidjohn

+0

質問はこれを行うPythonの透過的な方法についてです。 – jsbueno

1

機構は非常に簡単である

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では、1つのオブジェクトが存在する可能性がありますが、その固有値は、演算子の1つで使用される瞬間にouyterワールドでのみ認識されます。演算子は、二重のアンダースコアでは、クラスがオペレータが呼び出されたときに遅延コードを実行するための適切なコードを書くと、うまくいきます。

つまり、たとえばオブジェクトの値が文字列のように使用される場合、オブジェクトを使用するポーグラムの任意の部分は、ある時点で "__str__"強制変換メソッドを呼び出します。

たとえば、文字列のように動作するが、現在の時刻を示すオブジェクトを作成します。文字列は他の文字列(__ add__)に連結することができ、要求された長さ(__len__)を持つことができます。完全にintに収まるようにしたい場合は、すべてのメソッドをオーバーライドする必要があります。この考え方は、演算子の1つが呼び出されたときに実際の値を取得することです。そうでなければ、実際のオブジェクトを自由に変数に代入して渡すことができます。

、コンソール上にそれを使用して、あなたが持っている可能性があります:それだけでその値がその後

を必要とするとき、人はこのようないくつかのコードを持つことができる評価されます

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

場合遅延評価が必要な値は、オブジェクトが実際にどのように振る舞うのではなく、オブジェクトの属性(Peson.nameなど)です。これはさらに簡単です。 Pythonでは、すべてのオブジェクト属性が、ディスクリプタと呼ばれる特別な型であるため、属性にアクセスするたびに呼び出されるメソッドが実際に存在します。したがって、実際の値を確認するには、__get__という適切なメソッドを持つクラスを作成するだけで済みます。このメソッドは、属性が必要な場合にのみ呼び出されます。

Pythonには、簡単な記述子作成のためのユーティリティーもあります。これは、これをさらに簡単にする「property」キーワードです。プロパティーの最初のパラメーターとして属性を生成するコードであるメソッドを渡します。だから、

、怠惰な(と生きる)でイベントクラスを持つには時間が評価され、足すだけの問題である:

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

関連する問題