猿问

Python备忘录/延迟查找属性装饰器

最近,我浏览了现有的代码库,其中包含许多类,其中实例属性反映了存储在数据库中的值。我已经重构了许多这些属性,以便推迟它们的数据库查找。不会在构造函数中初始化,而只能在初读时进行初始化。这些属性不会在实例的整个生命周期内发生变化,但是它们是第一次计算的真正瓶颈,只有在特殊情况下才真正访问。因此,它们也可以在从数据库中检索出来之后进行缓存(因此,它适合于记忆的定义,其中输入只是“无输入”)。


我发现自己一遍又一遍地为各种类的各种属性键入以下代码片段:


class testA(object):


  def __init__(self):

    self._a = None

    self._b = None


  @property

  def a(self):

    if self._a is None:

      # Calculate the attribute now

      self._a = 7

    return self._a


  @property

  def b(self):

    #etc

我已经不知道有没有使用Python的现有装饰器来执行此操作?或者,是否有合理简单的方法来定义装饰器,从而做到这一点?


我正在Python 2.5下工作,但是2.6答案如果有很大不同,可能仍然很有趣。


注意

在Python包含许多现成的装饰器之前,就曾问过这个问题。我更新它只是为了更正术语。


繁星coding
浏览 421回答 3
3回答

婷婷同学_

对于各种强大的工具,我都使用bolton。作为该库的一部分,您具有cached属性:from boltons.cacheutils import cachedpropertyclass Foo(object):    def __init__(self):        self.value = 4    @cachedproperty    def cached_prop(self):        self.value += 1        return self.valuef = Foo()print(f.value)  # initial valueprint(f.cached_prop)  # cached property is calculatedf.value = 1print(f.cached_prop)  # same value for the cached property - it isn't calculated againprint(f.value)  # the backing value is different (it's essentially unrelated value)

凤凰求蛊

这是惰性属性装饰器的示例实现:import functoolsdef lazyprop(fn):    attr_name = '_lazy_' + fn.__name__    @property    @functools.wraps(fn)    def _lazyprop(self):        if not hasattr(self, attr_name):            setattr(self, attr_name, fn(self))        return getattr(self, attr_name)    return _lazypropclass Test(object):    @lazyprop    def a(self):        print 'generating "a"'        return range(5)互动环节:>>> t = Test()>>> t.__dict__{}>>> t.agenerating "a"[0, 1, 2, 3, 4]>>> t.__dict__{'_lazy_a': [0, 1, 2, 3, 4]}>>> t.a[0, 1, 2, 3, 4]

慕工程0101907

我为自己编写了此代码...用于真正的一次性计算的惰性属性。我喜欢它,因为它避免在对象上粘贴额外的属性,并且一旦激活就不会浪费时间检查属性是否存在,等等:import functoolsclass lazy_property(object):    '''    meant to be used for lazy evaluation of an object attribute.    property should represent non-mutable data, as it replaces itself.    '''    def __init__(self, fget):        self.fget = fget        # copy the getter function's docstring and other attributes        functools.update_wrapper(self, fget)    def __get__(self, obj, cls):        if obj is None:            return self        value = self.fget(obj)        setattr(obj, self.fget.__name__, value)        return valueclass Test(object):    @lazy_property    def results(self):        calcs = 1  # Do a lot of calculation here        return calcs注意:lazy_property该类是一个非数据描述符,这意味着它是只读的。添加__set__方法会阻止其正常工作。
随时随地看视频慕课网APP

相关分类

Python
我要回答