Храните кеш в файле functools.lru_cache в Python >= 3.2

Я использую @functools.lru_cache в Python 3.3. Я хотел бы сохранить кеш в файл, чтобы восстановить его, когда программа будет перезапущена. Как я мог сделать?

Изменить 1 Возможное решение: Нам нужно разборки любого вида вызываемого

Проблема травления __closure__:

_pickle.PicklingError: Can't pickle <class 'cell'>: attribute lookup builtins.cell failed

Если я попытаюсь восстановить функцию без нее, я получаю:

TypeError: arg 5 (closure) must be tuple

Ответ 1

Вы не можете делать то, что хотите, используя lru_cache, так как он не предоставляет API для доступа к кешу и может быть переписан на C в будущих выпусках. Если вы действительно хотите сохранить кеш, вам нужно использовать другое решение, которое дает вам доступ к кешу.

Достаточно просто написать кеш. Например:

from functools import wraps

def cached(func):
    @wraps(func)
    def wrapper(*args):
        try:
            return func.cache[args]
        except KeyError:
            func.cache[args] = result = func(*args)
            return result 
    wrapper.cache = {}  
    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 tracker для добавления дампов/нагрузок на lru_cache, но он не был принят/реализован, Возможно, в будущем можно будет иметь встроенную поддержку этих операций через lru_cache.

Ответ 2

Рассмотрите возможность использования joblib.Memory для постоянного кэширования на диске.

Поскольку диск огромен, нет необходимости в схеме кэширования LRU.

Ответ 3

Вы не должны касаться чего-либо внутри реализации декоратора, кроме общедоступного API, поэтому, если вы хотите изменить его поведение, вам, вероятно, нужно скопировать его реализацию и самостоятельно добавить необходимые функции. Обратите внимание, что кеш в настоящее время хранится в виде циклического двусвязного списка, поэтому вам нужно будет заботиться о его сохранении и загрузке.

Ответ 4

Вы можете использовать мою мою библиотеку, 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