该代码对于导入的依赖模块非常有效import another_module
,但是当模块导入函数时它失败了from another_module import some_func
。
我扩展了@redsk 的答案,试图对这些功能保持聪明。我还添加了一个黑名单,因为不幸的是typing
并且importlib
没有出现sys.builtin_module_names
(也许还有更多)。我还想防止重新加载我知道的一些依赖项。
我还跟踪重新加载的模块名称并返回它们。
在 Python 3.7.4 Windows 上测试:
def rreload(module, paths=None, mdict=None, base_module=None, blacklist=None, reloaded_modules=None):
"""Recursively reload modules."""
if paths is None:
paths = [""]
if mdict is None:
mdict = {}
if module not in mdict:
# modules reloaded from this module
mdict[module] = []
if base_module is None:
base_module = module
if blacklist is None:
blacklist = ["importlib", "typing"]
if reloaded_modules is None:
reloaded_modules = []
reload(module)
reloaded_modules.append(module.__name__)
for attribute_name in dir(module):
attribute = getattr(module, attribute_name)
if type(attribute) is ModuleType and attribute.__name__ not in blacklist:
if attribute not in mdict[module]:
if attribute.__name__ not in sys.builtin_module_names:
if os.path.dirname(attribute.__file__) in paths:
mdict[module].append(attribute)
reloaded_modules = rreload(attribute, paths, mdict, base_module, blacklist, reloaded_modules)
elif callable(attribute) and attribute.__module__ not in blacklist:
if attribute.__module__ not in sys.builtin_module_names and f"_{attribute.__module__}" not in sys.builtin_module_names:
if sys.modules[attribute.__module__] != base_module:
if sys.modules[attribute.__module__] not in mdict:
mdict[sys.modules[attribute.__module__]] = [attribute]
reloaded_modules = rreload(sys.modules[attribute.__module__], paths, mdict, base_module, blacklist, reloaded_modules)
reload(module)
return reloaded_modules
一些注意事项:
- 我不知道为什么某些 builtin_module_names 带有下划线前缀(例如
collections
列为_collections
,所以我必须进行双字符串检查。
callable()
返回True
课程,我想这是意料之中的,但这是我不得不将额外模块列入黑名单的原因之一。
至少现在我能够在运行时深度重新加载一个模块,并且从我的测试中我能够深入多个级别from foo import bar
并在每次调用时查看结果rreload()
(为长而丑陋的深度道歉,但黑色格式的版本在 SO 上看起来不太可读)