我在Python 3.3中使用@functools.lru_cache
。我想将缓存保存到文件中,以便在重新启动程序时恢复它。我该怎么办?
修改1 可能的解决方案:We need to pickle any sort of callable
问题腌制__closure__
:
_pickle.PicklingError: Can't pickle <class 'cell'>: attribute lookup builtins.cell failed
如果我尝试在没有它的情况下恢复功能,我会得到:
TypeError: arg 5 (closure) must be tuple
答案 0 :(得分:19)
您无法使用lru_cache
执行所需操作,因为它不提供访问缓存的API,并且在将来的版本中可能会在C中重写。如果您真的想要保存缓存,则必须使用不同的解决方案来访问缓存。
自己编写缓存很简单。例如:
from functools import wraps
def cached(func):
func.cache = {}
@wraps(func)
def wrapper(*args):
try:
return func.cache[args]
except KeyError:
func.cache[args] = result = func(*args)
return result
return wrapper
然后您可以将其应用为装饰者:
>>> @cached
... def fibonacci(n):
... if n < 2:
... return n
... return fibonacci(n-1) + fibonacci(n-2)
...
>>> fibonacci(100)
354224848179261915075L
并检索cache
:
>>> fibonacci.cache
{(32,): 2178309, (23,): 28657, ... }
然后,您可以随意挑选/取消缓存缓存并加载:
fibonacci.cache = pickle.load(cache_file_object)
我在python的问题跟踪器中找到了一个feature request来向lru_cache
添加转储/加载,但是它没有被接受/实现。也许将来可以通过lru_cache
为这些操作提供内置支持。
答案 1 :(得分:3)
考虑使用joblib.Memory对磁盘进行持久缓存。
由于磁盘非常庞大,因此不需要LRU缓存方案。
答案 2 :(得分:3)
您可以使用我的图书馆mezmorize
import random
from mezmorize import Cache
cache = Cache(CACHE_TYPE='filesystem', CACHE_DIR='cache')
@cache.memoize()
def add(a, b):
return a + b + random.randrange(0, 1000)
>>> add(2, 5)
727
>>> add(2, 5)
727
答案 3 :(得分:1)
除了公共API之外,你不应该触摸装饰器实现中的任何内容,所以如果你想改变它的行为,你可能需要复制它的实现并自己添加必要的函数。请注意,缓存当前存储为循环双向链表,因此在保存和加载时需要注意。
答案 4 :(得分:0)
我写的这些东西可能会有所帮助devcache。
它旨在帮助您加快长时间运行方法的迭代。它可以通过配置文件进行配置
@devcache(group='crm')
def my_method(a, b, c):
...
@devcache(group='db')
def another_method(a, b, c):
...
缓存可以刷新或与 yaml 配置文件一起使用,例如:
refresh: false # refresh true will ignore use_cache and refresh all cached data
props:
1:
group: crm
use_cache: false
2:
group: db
use_cache: true
将刷新 my_method
的缓存并使用 another_method
的缓存。
它不会帮助您腌制可调用对象,但它会执行缓存部分,并且可以直接修改代码以添加专门的序列化。