如何创建一个变量,其值在文件重新加载时保持不变?
How to create a variable whose value persists across file reload?
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。我想我可以关注 How do I check if a variable exists? :
if 'cache' not in globals():
cache = {}
但由于某种原因它看起来不像 "Pythonic"...
如果是 TRT,请告诉我!
回复评论:
- 我不对交叉调用持久性感兴趣;我 已经在处理了。
- 我 我 痛苦地意识到重新加载会改变 class 元对象,我 我 已经在处理它了。
cache
中的值很大,我不能每次都去磁盘。
由于重新加载的重点是确保执行的模块代码是第二次 运行,因此基本上没有办法避免某种 "reload detection."
您使用的代码似乎是您所引用问题中给出的最佳答案。
这里有几个选项。一种是使用临时文件作为缓存的持久存储,并在每次加载模块时尝试加载:
# 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
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。我想我可以关注 How do I check if a variable exists? :
if 'cache' not in globals():
cache = {}
但由于某种原因它看起来不像 "Pythonic"... 如果是 TRT,请告诉我!
回复评论:
- 我不对交叉调用持久性感兴趣;我 已经在处理了。
- 我 我 痛苦地意识到重新加载会改变 class 元对象,我 我 已经在处理它了。
cache
中的值很大,我不能每次都去磁盘。
由于重新加载的重点是确保执行的模块代码是第二次 运行,因此基本上没有办法避免某种 "reload detection."
您使用的代码似乎是您所引用问题中给出的最佳答案。
这里有几个选项。一种是使用临时文件作为缓存的持久存储,并在每次加载模块时尝试加载:
# 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