有没有一种简单的方法可以在对象级别记忆(和刷新)Python 上的属性?

Is there an easy way to memoize (and flush) properties on Python at object level?

我正在寻找一种缓存对象属性的方法。在我的例子中,我想对象会随着时间的推移而改变,所以 属性 的记忆值应该是可刷新的。在纯 python 中,我希望有这样的行为:

class Foo:
  def __init__(self, text: str):
    self._text  = text
    self._bar = None

  def flush(self):
     self._bar = None

  def update_text(self, text: str):
     self._text = text 
     self.flush()

  @property
  def bar(self):
    if self._bar is None:
      print('Computing bar...')
      self._bar = f'Computation with "{self._text}".'
    return self._bar

foo1 = Foo('Dog')
foo2 = Foo('Fish')

print(foo1.bar)
# Computing bar...
# Computation with "Dog".

print(foo1.bar)
# Computation with "Dog".

print(foo2.bar)
# Computing bar...
# Computation with "Fish".

print(foo2.bar)
# Computation with "Fish".

foo1.update_text('Cat')

print(foo1.bar)
# Computing bar...
# Computation with "Cat".

print(foo1.bar)
# Computation with "Cat".

print(foo2.bar)
# Computation with "Fish".

然后,如您所见,我想缓存 Foo.bar 属性。我的方法是定义一个初始化为 None 的私有 属性,然后分配并刷新以获得记忆行为。

现在,我的问题是是否有一些方法、库、方法或技术可以在不需要私有 属性 的情况下获得这种行为(假设您有一些可记忆的属性在 class).

我正在阅读标准库 (https://docs.python.org/3/library/functools.html) 中的 @lru_cache() 装饰器(以及最新的 @cached_property),但我意识到 cache_clear() 方法删除了class.

的所有实例的记忆值

我在想一种可能的解决方案是使用不可变对象,但该解决方案并不如我所愿,因为可能会出现我只想刷新其中一个属性记忆的情况。

感谢@sanyash 对问题评论的讨论。

有一个 cached_property 包 (https://pypi.org/project/cached-property/) 提供了请求的行为。使用cached_property的例子如下:

from cached_property import cached_property


class Foo:

    def __init__(self, text: str):
        self._text = text

    def flush(self):
        del self.__dict__['bar']

    def update_text(self, text: str):
        self._text = text
        self.flush()

    @cached_property
    def bar(self):
        print('Computing bar...')
        return f'Computation with "{self._text}".'


foo1 = Foo('Dog')
foo2 = Foo('Fish')

print(foo1.bar)
# Computing bar...
# Computation with "Dog".

print(foo1.bar)
# Computation with "Dog".

print(foo2.bar)
# Computing bar...
# Computation with "Fish".

print(foo2.bar)
# Computation with "Fish".

foo1.update_text('Cat')

print(foo1.bar)
# Computing bar...
# Computation with "Cat".

print(foo1.bar)
# Computation with "Cat".

print(foo2.bar)
# Computation with "Fish".

cached_property完美解决缓存属性

如果您对函数有类似的担忧,methodtools 适用于每个实例。

import methodtools

class Foo:
  @methodtools.lru_cache(maxsize=128)
  def bar(self, a, b, c):
    return something_using_parameters