Python交换sys.modules不像直觉

时间:2017-02-09 17:03:48

标签: python python-3.x python-import

我正在尝试设置字典sys.modules,同时处理another question的答案并遇到了一些有趣的事情。链接的问题涉及删除导入模块的所有影响。根据{{​​3}},我想到了在导入后从sys.modules删除所有新模块的想法。我最初的实现是执行以下操作(使用numpy作为加载和卸载模块进行测试):

# Load the module
import sys
mod_copy = sys.modules.copy()
print('numpy' in mod_copy, 'numpy' in sys.modules) # False False
import numpy
print('numpy' in mod_copy, 'numpy' in sys.modules) # False True
print(id(numpy)) # 45138472

打印输出显示numpy已成功导入,浅色副本未按预期方式包含它。

现在我的想法是通过将mod_copy交换回sys.modules来卸载模块,然后删除对模块的本地引用。理论上应该删除对它的所有引用(也可能是它):

sys.modules = mod_copy
del numpy
print('numpy' in sys.modules) # False

这应该足以重新导入模块,但是当我这样做时

import numpy
print('numpy' in sys.modules) # False
print(id(numpy)) # 45138472

看来numpy模块没有重新加载,因为它与以前的id相同。它不会显示在sys.modules中,尽管import语句没有引发错误并且似乎成功完成(即本地命名空间中存在numpy模块)。

另一方面,我在another post中对链接问题的实现看起来确实很好。它直接修改字典而不是交换出来:

import sys
mod_copy = sys.modules.copy()
print('numpy' in mod_copy, 'numpy' in sys.modules) # False False
import numpy
print('numpy' in mod_copy, 'numpy' in sys.modules) # False True
print(id(numpy)) # 35963432

for m in list(sys.modules):
    if m not in mod_copy:
        del sys.modules[m]
del numpy
print('numpy' in sys.modules) # False

import numpy
print('numpy' in sys.modules) # True
print(id(numpy)) # (54941000 != 35963432)

我在Anaconda安装上使用Python 3.5.2。我最感兴趣的是关于Python 3的解释,但我也对Python 2.7+感到好奇。

我唯一可以想到的是sys维护对sys.modules的另一个引用,并使用该内部引用,无论我对公众做什么。我不确定这涵盖了一切,所以我想知道真正发生了什么。

1 个答案:

答案 0 :(得分:2)

即使在Python 3.5中,导入实现的一部分是still written in C,该部分使用PyThreadState_GET()->interp->modules来检索模块缓存,而不是通过sys.modules属性。您的导入是通过其中一个代码路径在旧numpy中找到sys.modules

sys.modules并非旨在被替换。 docs提到替换它可能会出乎意料地表现出来:

  

这可以被操纵以强制重新加载模块和其他技巧。但是,替换字典不一定会按预期工作,从字典中删除基本项可能会导致Python失败。