Запоминать весь блок / анонимную функцию чисто в Python - PullRequest
2 голосов
/ 08 апреля 2019

Какой самый чистый способ (со стороны пользователя) запоминать весь блок вычислений (многострочный лямбда, если таковые были созданы) в Python?

С memoize я намереваюсь обобщить: «Если результат уже был вычислен, просто загрузите его откуда-то. В противном случае вычислите его и сохраните где-нибудь».

Мое текущее решение (для записи чего-то, что кэширует на диск результат произвольных вычислений):

  1. Имеется один декоратор, который выполняет кеширование (в качестве параметра он принимает имя файла, куда его сохранить / загрузить):
from functools import wraps

def disk_cache(filename):
    def decorator(compute_result_func):
        @wraps(compute_result_func) # don't shadow function's docstring
        def wrapped(*args, **kwargs):
            if not os.path.exists(filename):
                # compute and save
                print "compute"
                result = compute_result_func()
                print "save"
                pickle.dump(result, open(filename, 'wb'))
            else:
                # load
                print "load"
                result = pickle.load(open(filename, 'rb'))
            return result
        return wrapped
    return decorator
  1. Всякий раз, когда у меня есть блок вычислений, который я хотел бы запомнить, я заключаю его в функцию с обобщенным именем (я бы использовал многострочную лямбду, если бы мог), которая ничего не берет (просто захватывает переменные, которые находятся в большая область) и возвращает один результат. Я украшаю эту функцию своим декоратором и немедленно вызываю функцию.
@disk_cache(filename='/path/to/dump.pkl')
def multi_line_lambda():
    # do some stuff
    x = 2 ** 2
    y = 7
    return x + y
multi_line_lambda()

Можно ли использовать шаблон, который синтаксически чище? Что-то вроде

with cache(filename):
    do x
    do y
    return result # which is actually just loaded if already existing

1 Ответ

0 голосов
/ 08 апреля 2019

Я исследовал этот точный вопрос в прошлом (бесстыдный плагин: здесь мой результат ) и обнаружил, что лучше использовать ваш существующий подход.Однако, если вы хотите злоупотребить синтаксисом Python, вот как вы можете это сделать:

def disk_cache(filename):
    def decorator(compute_result_func):
        if not os.path.exists(filename):
            result = compute_result_func()
            pickle.dump(result, open(filename, 'wb'))
        else:
            result = pickle.load(open(filename, 'rb'))
        return result
    return decorator

Сейчас,

@disk_cache(filename='/path/to/dump.pkl')
def calculated_stuff():
    # do some stuff
    x = 2 ** 2
    y = 7
    return x + y
# at this point, calculated_stuff() already contains the result (11)

Пожалуйста, помните, что это грязная практика.Не делайте этого в коде, который кто-то другой может прочитать

...