仅从一个包中重新加载模块

时间:2017-03-18 04:22:25

标签: python python-import

如何在不从任何其他外部软件包导入模块的情况下深度重新加载软件包?

例如,重新加载以下内容:

# example_pkg.py
import logging  # do not reload this stdlib package
import example_pkg.ex_mod  # reload this module

IPython的deepreload模块无法为导入指定白名单,并在重新加载期间使用模块级变量,这使得线程环境不可靠。

有一个与此问题相似的问题before,但它侧重于发现依赖关系(评论中的mentioned),而不仅仅是在单个包中。

1 个答案:

答案 0 :(得分:1)

使用sysimportlib模块,可以编写一个函数来从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,它可以用不同的对象替换解释器中对象的所有引用(通常用于调试目的)。