考虑以下几点:

@property
def name(self):

    if not hasattr(self, '_name'):

        # expensive calculation
        self._name = 1 + 1

    return self._name

我是新来的,但我认为缓存可以分解成一个装饰器。只是我没有找到一个这样的;)

PS,真正的计算不依赖于可变值


当前回答

除了Memoize示例,我还找到了以下python包:

cachepy;它允许设置ttl和\或缓存函数的调用次数;此外,还可以使用加密的基于文件的缓存… percache

其他回答

从Python 3.2开始,有一个内置的装饰器:

@functools。lru_cache(最大容量= 100,输入= False)

装饰器使用一个可记忆可调用对象来包装函数,该可调用对象最多保存maxsize最近的调用。当使用相同的参数周期性地调用昂贵的或I/O绑定的函数时,它可以节省时间。

用于计算斐波那契数的LRU缓存示例:

from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

>>> print([fib(n) for n in range(16)])
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]

>>> print(fib.cache_info())
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)

如果你被Python 2困住了。X,这里是其他兼容的内存库列表:

functools32 | PyPI |源代码 repoze。lru | PyPI |源代码 pylru | PyPI |源代码 补丁。functools_lru_cache | PyPI |源代码

听起来好像您不是在要求一个通用的记忆化装饰器(也就是说,您对想要缓存不同参数值的返回值的一般情况不感兴趣)。也就是说,你想要这样:

x = obj.name  # expensive
y = obj.name  # cheap

而一个通用的记忆装饰器会给你这样的:

x = obj.name()  # expensive
y = obj.name()  # cheap

我认为方法调用语法是更好的风格,因为它暗示了昂贵计算的可能性,而属性语法暗示了快速查找。

[更新:我之前链接并引用的基于类的记忆化装饰器不适用于方法。我用decorator函数替换了它。如果你愿意使用通用的记忆装饰器,这里有一个简单的:

def memoize(function):
  memo = {}
  def wrapper(*args):
    if args in memo:
      return memo[args]
    else:
      rv = function(*args)
      memo[args] = rv
      return rv
  return wrapper

使用示例:

@memoize
def fibonacci(n):
  if n < 2: return n
  return fibonacci(n - 1) + fibonacci(n - 2)

可以在这里找到另一个对缓存大小有限制的内存装饰器。

免责声明:我是kids.cache的作者。

你应该检查孩子。Cache,它提供了一个在python 2和python 3上工作的@cache装饰器。没有依赖关系,大约100行代码。它的使用非常简单,例如,在你的代码中,你可以这样使用:

pip install kids.cache

Then

from kids.cache import cache
...
class MyClass(object):
    ...
    @cache            # <-- That's all you need to do
    @property
    def name(self):
        return 1 + 1  # supposedly expensive calculation

或者你可以把@cache装饰器放在@属性之后(同样的结果)。

在属性上使用缓存被称为惰性求值。缓存可以做更多的事情(它适用于带有任何参数、属性、任何类型的方法,甚至是类的函数……)对于高级用户,儿童。cache支持cachetools,它为python 2和python 3提供了漂亮的缓存存储(LRU, LFU, TTL, RR缓存)。

重要提示:孩子的默认缓存存储。缓存是一个标准字典,不建议长时间运行具有不同查询的程序,因为它会导致缓存存储不断增长。对于这种用法,你可以使用插件其他缓存存储使用例如(@cache(use=cachetools.LRUCache(maxsize=2))来装饰你的函数/属性/类/方法…)

class memorize(dict):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args):
        return self[args]

    def __missing__(self, key):
        result = self[key] = self.func(*key)
        return result

示例使用:

>>> @memorize
... def foo(a, b):
...     return a * b
>>> foo(2, 4)
8
>>> foo
{(2, 4): 8}
>>> foo('hi', 3)
'hihihi'
>>> foo
{(2, 4): 8, ('hi', 3): 'hihihi'}

如果你正在使用Django并且想要缓存视图,请参阅Nikhil Kumar的回答。

但是如果你想缓存任何函数的结果,你可以使用django-cache-utils。

它重用了Django缓存,并提供了易于使用的缓存装饰器:

from cache_utils.decorators import cached

@cached(60)
def foo(x, y=0):
    print 'foo is called'
    return x+y