importlib.reload应该在Python 3.6中恢复已删除的属性吗?

时间:2018-02-15 17:44:20

标签: python python-3.x cpython python-internals

我正在调查这两个相关问题:herehere

我看到Python 3.6中没有出现的行为,这与Python 2.7(和3.4)中使用普通reload的行为不同。也就是说,似乎在模块初始化期间或在重新加载期间重新执行模块时将填充的模块属性在使用del删除其本地名称后不会恢复...请参阅下文:< / p>

对于Python 3.6:

In [1]: import importlib

In [2]: import math

In [3]: del math.cos

In [4]: math.cos
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-05b06e378197> in <module>()
----> 1 math.cos

AttributeError: module 'math' has no attribute 'cos'

In [5]: math = importlib.reload(math)

In [6]: math.cos
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-6-05b06e378197> in <module>()
----> 1 math.cos

AttributeError: module 'math' has no attribute 'cos'

In [7]: importlib.reload(math)
Out[7]: <module 'math' from '/home/ely/anaconda/envs/py36-keras/lib/python3.6/lib-dynload/math.cpython-36m-x86_64-linux-gnu.so'>

In [8]: math.cos
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-05b06e378197> in <module>()
----> 1 math.cos

AttributeError: module 'math' has no attribute 'cos'

对于Python 2.7(和Python 3.4):

In [1]: import math

In [2]: del math.cos

In [3]: math.cos
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-05b06e378197> in <module>()
----> 1 math.cos

AttributeError: 'module' object has no attribute 'cos'

In [4]: reload(math)
Out[4]: <module 'math' from '/home/ely/anaconda/lib/python2.7/lib-dynload/math.so'>

In [5]: math.cos
Out[5]: <function math.cos>

我已尝试将importlib的详细信息从source code向下追溯到C-level module exec function,但我无法看到任何会导致其无法编写重新初始化的逻辑{ {1}}将属性重新置于模块范围全局变量的模块的dict中。

我怀疑它是C级重新执行逻辑中的某种类型的错误,它会查看模块字典中找到的属性名称(从以前的任何时候开始存在的属性名称)导入,并且可能已经变异以删除属性,就像在我的示例中一样),然后当使用cos将模块的执行副作用写入该字典时,它的跳过键名称(如exec)不存在于模块的命名空间中,这与Python 2.7的行为不同。

1 个答案:

答案 0 :(得分:2)

我认为这是PEP 489的一种(意图?无意的?)效果,是对扩展模块初始化的彻底检查。 PEP包括以下部分:

  

模块重新加载

     

使用importlib.reload()重新加载扩展模块将继续无效,但重新设置除外   与导入相关的属性。

     

由于共享库加载的限制(dlopen on POSIX和   在Windows上的LoadModuleEx),通常不可能加载   修改后的库在磁盘上更改后。

     

用于重新加载的用例,而不是尝试新版本的   模块太少了,不能要求所有模块作者继续重新加载   心神。如果需要类似重载的功能,作者可以导出   它的专用功能。

在实施PEP 489的提交中引入了似乎对此行为负责的code change

即使Python 3.4也不支持从更改的文件中真正重新加载扩展模块;它最接近的是初始化后模块的dict的save a copy代码和copy the contents重新加载到模块的实际dict中的代码。该代码still exists,但不再触发重新加载,而且我不知道是否有意触发重新加载。我相信代码目前仅用于子解释器。