“del sys.modules [module]”实际上做了什么?

时间:2017-04-03 09:48:55

标签: python module sys python-internals

众所周知,您可以del sys.modules[module]删除导入的模块。所以我在想:这与重写sys.modules有什么不同?一个有趣的事实是,重写sys.modules无法真正删除模块。

# a_module.py
print("a module imported")

然后

import sys

def func1():
    import a_module
    # del sys.modules['a_module']
    sys.modules = {
        k: v for k, v in sys.modules.items() if 'a_module' not in k}
    print('a_module' not in sys.modules)  # True

def func2():
    import a_module

func1()  # a module imported
func2()  # no output here

如果我使用del sys.modules['a_module'],则调用func2()也会打印a module imported,这意味着a_module已成功删除。

我的问题是:除了更改词典外,del sys.modules[module]实际上做了什么?

1 个答案:

答案 0 :(得分:8)

sys.modules规范数据结构的 Python可访问引用,用于跟踪导入的模块。从该字典中删除名称意味着将来导入模块的任何尝试都将导致Python从头开始加载模块。

换句话说,无论何时使用import语句,Python所做的第一件事就是检查sys.modules引用的字典是否已有该模块的条目并继续下一步(绑定)当前命名空间中的名称)而不先加载模块。如果您从sys.modules删除条目,那么Python将无法找到已加载的模块并再次加载。

请注意这里关于 Python-accessible 的谨慎措辞。实际字典存在于Python堆上,而sys.modules只是对它的一个引用。您通过分配到sys.modules 将该引用替换为该引用与另一个字典。但是,解释器有对它的更多引用;他们只是无法从Python代码访问,无论如何都没有ctypes技巧来访问C-API。

请注意,这是explicitly documented

  

但是,替换字典不一定会按预期工作,从字典中删除基本项可能会导致Python失败。

在C-API中,您必须使用PyThreadState_Get()->interp->modules来获取字典的内部引用。