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