考虑以下几点:
@property
def name(self):
if not hasattr(self, '_name'):
# expensive calculation
self._name = 1 + 1
return self._name
我是新来的,但我认为缓存可以分解成一个装饰器。只是我没有找到一个这样的;)
PS,真正的计算不依赖于可变值
考虑以下几点:
@property
def name(self):
if not hasattr(self, '_name'):
# expensive calculation
self._name = 1 + 1
return self._name
我是新来的,但我认为缓存可以分解成一个装饰器。只是我没有找到一个这样的;)
PS,真正的计算不依赖于可变值
当前回答
尝试joblib https://joblib.readthedocs.io/en/latest/memory.html
from joblib import Memory
memory = Memory(cachedir=cachedir, verbose=0)
@memory.cache
def f(x):
print('Running f(%s)' % x)
return x
其他回答
如果你正在使用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
免责声明:我是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))来装饰你的函数/属性/类/方法…)
functools。缓存已经在Python 3.9 (docs)中发布:
from functools import cache
@cache
def factorial(n):
return n * factorial(n-1) if n else 1
在以前的Python版本中,早期的答案之一仍然是有效的解决方案:使用lru_cache作为普通缓存,没有限制和lru特性。(文档)
如果maxsize设置为None,将禁用LRU特性,并将缓存 可以不受束缚地成长。
这里有一个更漂亮的版本:
cache = lru_cache(maxsize=None)
@cache
def func(param1):
pass
如果你正在使用Django框架,它有这样一个属性来缓存API的视图或响应 使用@cache_page(time),也可以有其他选项。
例子:
@cache_page(60 * 15, cache="special_cache")
def my_view(request):
...
更多细节可以在这里找到。
函数缓存简单解决方案
TTL(时间到生命)和max_entries
当修饰函数接受不可哈希类型作为输入(例如dicts)时,不工作 可选参数:TTL(每个条目的生存时间) 可选参数:max_entries(如果缓存参数组合太多,不会使存储混乱) 确保该函数没有重要的副作用
示例使用
import time
@cache(ttl=timedelta(minutes=3), max_entries=300)
def add(a, b):
time.sleep(2)
return a + b
@cache()
def substract(a, b):
time.sleep(2)
return a - b
a = 5
# function is called with argument combinations the first time -> it takes some time
for i in range(5):
print(add(a, i))
# function is called with same arguments again? -> will answer from cache
for i in range(5):
print(add(a, i))
复制装饰器代码
from datetime import datetime, timedelta
def cache(**kwargs):
def decorator(function):
# static function variable for cache, lazy initialization
try: function.cache
except: function.cache = {}
def wrapper(*args):
# if nothing valid in cache, insert something
if not args in function.cache or datetime.now() > function.cache[args]['expiry']:
if 'max_entries' in kwargs:
max_entries = kwargs['max_entries']
if max_entries != None and len(function.cache) >= max_entries:
now = datetime.now()
# delete the the first expired entry that can be found (lazy deletion)
for key in function.cache:
if function.cache[key]['expiry'] < now:
del function.cache[key]
break
# if nothing is expired that is deletable, delete the first
if len(function.cache) >= max_entries:
del function.cache[next(iter(function.cache))]
function.cache[args] = {'result': function(*args), 'expiry': datetime.max if 'ttl' not in kwargs else datetime.now() + kwargs['ttl']}
# answer from cache
return function.cache[args]['result']
return wrapper
return decorator