如何在 Python 中记住一个属性?

mch*_*hen 2 python properties memoization

考虑以下最小示例:

class Foo(object):

    def __init__(self):
        self.b = self.a = 1

    @property
    def sum(self):
        print 'Recalculating sum'
        return self.a + self.b

foo = Foo()
print foo.sum
print foo.sum   # Prints 'Recalculating sum' even though neither a or b has changed since previous call
foo.a = 2
print foo.sum   # a has been changed to 2 so recalculation is necessary
Run Code Online (Sandbox Code Playgroud)

我想memoize的sum这样,如果self.a和self.b不改变,那么我们就需要重新计算保留的财产。

只有在更改self.a或self.b更改时才应重新计算该属性——是否有一种简单的方法可以做到这一点?

Jay*_*Jay 5

蟒蛇3:

from functools import lru_cache as memoized

@property
@memoized(maxsize=1)
def sum(self):
    return self.a + self.b
Run Code Online (Sandbox Code Playgroud)

蟒蛇 3.8

from functools import cache

@cached_property
def sum(self):
    return self.a + self.b
Run Code Online (Sandbox Code Playgroud)

  • 这种方法在这里不合适。因为“a”和“b”不是函数的参数,所以记忆不会考虑它们。即使“a”和“b”发生变化,您也将始终得到相同的结果。 (5认同)
  • 还有“@cached_property”(从 3.8 开始)。我不确定它与在“@cache”之上堆叠“@property”有何不同,以及哪个更适合哪种用例。[文档](https://docs.python.org/3/library/functools.html#functools.cached_property)在某种程度上解释了它。 (2认同)

bru*_*ers 1

a使用和的属性b并清除设置器中的缓存:

class Foo(object):

    def __init__(self):
        self.a = 1
        self.b = 1

    @property
    def a(self):
        return self._a

    @a.setter
    def a(self, value):
        self._a = value
        self._clearsum()

     @property
    def b(self):
        return self._b

    @b.setter
    def b(self, value):
        self._b = value
        self._clearsum()

    def _clearsum(self):
        self._sum = None

    @property
    def sum(self):
        if self._sum is None:
            self._sum = self.a + self.b
        return self._sum
Run Code Online (Sandbox Code Playgroud)

或者,如果您想要更通用的东西,您也可以检查一下: 将计算值存储在对象中

编辑:最近有人建议添加self._sum = None“__init__访问总和时避免错误”,但这实际上是不必要的 - __init__invokes a.setter,它调用_clearsum,它设置_sum属性,所以它保证self._sum将被创建。