Как создать переменную, значение которой сохраняется при перезагрузке файла? - PullRequest
0 голосов
/ 15 февраля 2019

Common Lisp имеет defvar, который создает глобальную переменную, но устанавливает ее только в том случае, если она новая: если она уже существует, она не сбрасывается.Это полезно при перезагрузке файла из долгого интерактивного процесса, потому что он хранит данные.

Я хочу то же самое в Python.У меня есть файл foo.py, который содержит что-то вроде этого:

cache = {}
def expensive(x):
    try:
        return cache[x]
    except KeyError:
        # do a lot of work
        cache[x] = res
        return res

Когда я делаю imp.reload(foo), значение cache теряется, чего я хочу избежать.

Как сохранить cache через reload?

PS .Я предполагаю, что могу следовать Как проверить, существует ли переменная? :

if 'cache' not in globals():
   cache = {}

, но по какой-то причине она не выглядит "Pythonic" ... Если это TRT, пожалуйста, скажите мне об этом!

Отвечая на комментарии:

  • Я не заинтересован в постоянстве перекрестных вызовов;Я уже обрабатываю это.
  • I Я мучительно осознаю, что перезагрузка изменяет мета-объекты класса, и я am уже обрабатываю это.
  • Значения в cache огромны, я не могу зайти на диск каждый раз, когда они мне нужны.

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

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

# foo.py
import tempfile
import pathlib
import pickle

_CACHE_TEMP_FILE_NAME = '__foo_cache__.pickle'
_CACHE = {}

def expensive(x):
    try:
        return _CACHE[x]
    except KeyError:
        # do a lot of work
        _CACHE[x] = res
        _save_cache()
        return res

def _save_cache():
    tmp = pathlib.Path(tempfile.gettempdir(), _CACHE_TEMP_FILE_NAME)
    with tmp.open('wb') as f:
        pickle.dump(_CACHE, f)

def _load_cache():
    global _CACHE
    tmp = pathlib.Path(tempfile.gettempdir(), _CACHE_TEMP_FILE_NAME)
    if not tmp.is_file():
        return
    try:
        with tmp.open('rb') as f:
            _CACHE = pickle.load(f)
    except pickle.UnpicklingError:
        pass

_load_cache()

Единственная проблема, связанная с этим, заключается в том, что вам нужно доверять среде, а не писатьчто-либо вредоносное вместо временного файла (модуль pickle не защищен от ошибочных или вредоносных данных).

Другой вариант - использовать другой модуль для кэша, который не перезагружается:

# foo_cache.py
Cache = {}

А потом:

# foo.py
import foo_cache

def expensive(x):
    try:
        return foo_cache.Cache[x]
    except KeyError:
        # do a lot of work
        foo_cache.Cache[x] = res
        return res
0 голосов
/ 15 февраля 2019

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

Появляется код, который вы используетебыть лучшим ответом из приведенных в вопросе, на который вы ссылаетесь.

...