【发布时间】:2018-07-26 13:39:00
【问题描述】:
我在 Python 3.6 中看到了我不希望出现的行为,这与在 Python 2.7(和 3.4)中使用纯 reload 的行为不同。即,似乎在模块初始化期间或在重新加载期间重新执行模块时填充的模块属性在使用del 删除其本地名称后不会恢复......见下文:
对于 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>
我尝试从source code 到C-level module exec function 追踪importlib 的详细信息,但我看不到任何逻辑会导致它无法将重新初始化的cos 属性写回模块范围全局变量的模块字典。
我怀疑这是 C 级重新执行逻辑中的某种错误,它查看模块字典中找到的属性名称(从以前导入时就存在的属性名称,并且可能被突变为删除了一个属性,就像在我的示例中一样),然后当使用exec 将模块的执行副作用写入该字典时,它会跳过模块名称空间中不存在的键名(如cos),这与 Python 2.7 的行为不同。
【问题讨论】:
-
来自文档:当一个模块被重新加载时,它的字典(包含模块的全局变量)被保留。阅读更多docs.python.org/3/library/importlib.html#importlib.reload
-
@Kasramvd 这并没有解释它。字典确实保留了,但是为什么在重新执行模块时没有将新键(如
cos)添加到字典中?不幸的是,它重用现有模块字典的细节似乎并没有解决这个问题,因为它在 Python 2.7 中也是如此,只是它根据需要使用模块属性重新填充它。 -
请注意,第二个版本也适用于 python 3.4。所以变化一定出现在两者之间
-
@user2357112 但
math显然是为重新加载而设计的,因为它适用于 Python 2.7 和 Python 3.4。我不相信文档中的评论也适用于这个问题。
标签: python python-3.x cpython python-internals