【问题标题】:Should importlib.reload restore a deleted attribute in Python 3.6?importlib.reload 是否应该在 Python 3.6 中恢复已删除的属性?
【发布时间】:2018-07-26 13:39:00
【问题描述】:

我正在研究这两个相关的问题:herehere

我在 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 codeC-level module exec function 追踪importlib 的详细信息,但我看不到任何逻辑会导致它无法将重新初始化的cos 属性写回模块范围全局变量的模块字典。

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

【问题讨论】:

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


【解决方案1】:

我相信这是PEP 489 的(有意的?无意的?)效果,扩展模块初始化的大修。 PEP 包括以下部分:

模块重新加载

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

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

除了尝试新版本之外的重新加载用例 模块太少了,不需要所有模块作者继续重新加载 头脑。如果需要类似重新加载的功能,作者可以导出一个 它的专用功能。

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

即使是 Python 3.4 也不支持真正从更改的文件重新加载扩展模块;最接近的代码是初始化后模块字典的save a copycopy the contents 在重新加载时回到模块的实际字典。那个代码stillexists,但它不再被触发重新加载,我不知道它是否打算被触发重新加载。我相信该代码目前仅用于子解释器。

【讨论】:

  • 我想除了“这只是为 Python 3.6 提交的随机事情,因为开发人员认为这本质上是未定义的行为”之外,没有任何令人满意的答案。感谢您链接代码更改。我确实认为我们应该小心您的行,“Python 3.4 不支持真正从更改的文件重新加载扩展模块......”问题是 not 关于重新加载动态扩展时它的源发生了变化,而只是一个问题,为什么不总是尝试重新初始化,尤其是当底层模块没有发生变化时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-16
相关资源
最近更新 更多