如何在不从任何其他外部软件包导入模块的情况下深度重新加载软件包?
例如,重新加载以下内容:
# example_pkg.py
import logging # do not reload this stdlib package
import example_pkg.ex_mod # reload this module
IPython的deepreload
模块无法为导入指定白名单,并在重新加载期间使用模块级变量,这使得线程环境不可靠。
答案 0 :(得分:1)
使用sys
和importlib
模块,可以编写一个函数来从Python的导入缓存中删除软件包及其模块。这允许程序包在重新导入时重新加载其子模块。
import sys
import importlib
from types import ModuleType
def deep_reload(m: ModuleType):
name = m.__name__ # get the name that is used in sys.modules
name_ext = name + '.' # support finding sub modules or packages
del m
def compare(loaded: str):
return (loaded == name) or loaded.startswith(name_ext)
all_mods = tuple(sys.modules) # prevent changing iterable while iterating over it
sub_mods = filter(compare, all_mods):
for pkg in sub_pkgs:
del sys.modules[pkg] # remove sub modules and packages from import cache
return importlib.import_module(name)
此代码可以使用Lock
进行扩展,以使其具有线程安全性:
from threading import Lock
sys_mod_lock = Lock() # all accesses to sys.modules must be programmed to acquire this lock first
# this means do not use any builtin import mechanism such as the 'import' statement once the following function is being used
# instead use importlib's import_module function while sys_mod_lock is acquired
def tsafe_reload(m: ModuleType):
with sys_mod_lock:
return deep_reload(m)
注意:这些功能附带标准库reload
中的一个注意事项。将保留程序中其他位于旧程序包中的引用,并且不会自动替换。为此,您可以查看globalsub
,它可以用不同的对象替换解释器中对象的所有引用(通常用于调试目的)。