2017-02-09 41 views
2

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

# 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模块),但它并未出现在sys.modules中。

另一方面,我在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的另一个引用,并且使用该内部引用,而不管我对公众做什么。我不确定这是否涵盖了所有内容,所以我想知道实际情况。

+0

在Python 2中,我希望导入机制使用自己的内部引用模块缓存,独立于'sys.modules'引用,但据我所知,在Python 3.5中,导入机器](https://hg.python.org/cpython/file/3.5/Lib/importlib/_bootstrap。py)访问sys模块对象的'modules'属性,只要它需要模块缓存。我不知道为什么在替换字典和重新导入'numpy'后,'numpy''将无法显示在'sys.modules'中。 – user2357112

+0

@ user2357112。那么,它看起来有一些内部参考,因为'numpy'的'id'在两次导入后都是相同的。就好像它正在使用原来的“模块”字典并忽略被换入的字典。 –

+0

“id”相同并不意味着太多;如果不同的对象具有不重叠的生命周期,则具有相同的ID是相当常见的。要查看它是否使用了相同的对象,您需要设置类似'numpy.lookatme = 3'的内容,然后查看该修改是否仍然显示。 – user2357112

回答

2

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

sys.modules不是被设计成被替换的。 docs提到替换它可能会出乎意料:

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

+0

这是有道理的。所以基本上有不止一个引用浮动的字典。你认为这是值得一提的邮件列表或错误报告? –

+0

另外,3.6的行为是否改变? –

+0

@MadPhysicist:Python 3.6上的代码看起来差不多,但我没有测试它。至于错误报告,没有。您不希望能够替换模块缓存。从[docs](https://docs.python.org/3/library/sys.html#sys.modules):“这可以被操纵来强制重新加载模块和其他技巧。但是,**替换字典将不一定按预期工作**并删除字典中的重要项目可能会导致Python失败。“ – user2357112