python-3.x - Сохранить кеш в файл functools.lru_cache в Python>=3.2




memoization (5)

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

Я использую @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

Вы не можете делать то, что хотите, используя 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 для добавления дампов / загрузок в lru_cache , но он не был принят / реализован. Возможно, в будущем будет возможно иметь встроенную поддержку этих операций через lru_cache .


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

Подумайте об использовании joblib.Memory для постоянного кэширования на диск.

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


«Лучшее» - частично субъективное решение. Используйте кортежи для небольших наборов возвратов в общем случае, когда неизменяемый допустим. Кортеж всегда предпочтительнее списка, когда изменчивость не является требованием.

Для более сложных возвращаемых значений или для случая, когда формальность является ценной (т. Е. Код с высоким значением), именованный кортеж лучше. Для наиболее сложного случая объект обычно лучше всего подходит. Однако это действительно имеет значение. Если имеет смысл возвращать объект, потому что это то, что вы, естественно, имеете в конце функции (например, шаблон Factory), затем возвращаете объект.

Как сказал мудрец:

Преждевременная оптимизация - это корень всего зла (или, по крайней мере, большей части) в программировании.





python python-3.x memoization