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 为此包含许多现成的装饰器之前,有人问过这个问题。我更新它只是为了更正术语。

原文由 detly 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 443
2 个回答

对于各种很棒的实用程序,我使用的是 boltons

作为该库的一部分,您拥有 cachedproperty

 from boltons.cacheutils import cachedproperty

class Foo(object):
    def __init__(self):
        self.value = 4

    @cachedproperty
    def cached_prop(self):
        self.value += 1
        return self.value

f = Foo()
print(f.value)  # initial value
print(f.cached_prop)  # cached property is calculated
f.value = 1
print(f.cached_prop)  # same value for the cached property - it isn't calculated again
print(f.value)  # the backing value is different (it's essentially unrelated value)

原文由 Guy 发布,翻译遵循 CC BY-SA 3.0 许可协议

这是惰性属性装饰器的示例实现:

 import functools

def 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 _lazyprop

class Test(object):

    @lazyprop
    def a(self):
        print 'generating "a"'
        return range(5)

互动环节:

 >>> t = Test()
>>> t.__dict__
{}
>>> t.a
generating "a"
[0, 1, 2, 3, 4]
>>> t.__dict__
{'_lazy_a': [0, 1, 2, 3, 4]}
>>> t.a
[0, 1, 2, 3, 4]

原文由 Mike Boers 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题