我在寻找another question的答案时尝试设置字典sys.modules
并发现了一些有趣的事情。链接的问题涉及消除导入模块的所有影响。基于another post ,我提出了在导入后从 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
。尽管 import
语句没有引发错误并且似乎成功完成(即 numpy
> 模块存在于本地命名空间中)。
另一方面,我在 my answer 中所做的实现链接的问题似乎确实工作正常。它直接修改字典而不是交换它:
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
的另一个引用,并使用该内部引用,无论我对公共(public)一.但我不确定这是否涵盖了所有内容,所以我想知道到底发生了什么。
最佳答案
即使在 Python 3.5 中,导入实现的一部分也是 still written in C ,该部分使用 PyThreadState_GET()->interp->modules 来检索模块缓存,而不是通过 sys.modules 属性。您的导入是通过这些代码路径之一在旧的 sys.modules
中查找 numpy
。
sys.modules
并非旨在被替换。 docs提到替换它可能会出现意想不到的行为:
This can be manipulated to force reloading of modules and other tricks. However, replacing the dictionary will not necessarily work as expected and deleting essential items from the dictionary may cause Python to fail.
关于Python 换出 sys.modules 并不像直觉那样工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42142660/