importlib.reload是否应该在Python 3.6中恢复已删除的属性? [英] Should importlib.reload restore a deleted attribute in Python 3.6?

查看:69
本文介绍了importlib.reload是否应该在Python 3.6中恢复已删除的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究以下两个相关问题:此处和< a href = https://stackoverflow.com/questions/48808456/deleted-a-modules-function-on-interactive-how-to-re-import-importlib-reload-n>此处。



我看到了在Python 3.6中不期望的行为,这与在Python 2.7中使用普通 reload 的行为不同(和3.4)。即,在使用 del ...见下文:



对于Python 3.6:

 在[1]中:import importlib 

在[2]中:导入数学

在[3]中:del math.cos

在[ 4]:math.cos
---------------------------------------- -----------------------------------
AttributeError追溯(最近一次通话)
< ipython-input-4-05b06e378197>在< module>()
---->中1 math.cos

AttributeError:模块'math'没有属性'cos'

在[5]中:math = importlib.reload(math)

在[6]中:math.cos
----------------------------------- ----------------------------------------
AttributeError追溯(最近一次调用last)
< ipython-input-6-05b06e378197>在< module>()
---->中1 math.cos

AttributeError:模块'math'没有属性'cos'

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

在[8]中:math.cos
------------------------------ ---------------------------------------------
AttributeError追溯(最近一次通话)
< ipython-input-8-05b06e378197>在< module>()
---->中1 math.cos

AttributeError:模块'math'没有属性'cos'

对于Python 2.7(和 Python 3.4 ):

 在[1]中:导入数学

在[2]中:del math.cos

在[3]中:math.cos
-------------------- -------------------------------------------------- -----
AttributeError追溯(最近一次呼叫最近)
< ipython-input-3-05b06e378197>在< module>()
---->中1 math.cos

AttributeError:'module'对象没有属性'cos'

In [4]:reload(math)
Out [4]: <来自'/home/ely/anaconda/lib/python2.7/lib-dynload/math.so的模块'math''>

输入[5]:math.cos
输出[5]:<函数math.cos>

我已经尝试从源代码直至 C级模块exec函数,而且我看不到任何会导致它无法写入重新初始化 cos 属性回到模块作用域全局变量的模块中。



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

解决方案

我认为这是(打算?意外?) PEP 489 的效果,扩展模块初始化。 PEP包括以下部分:


模块重新加载


使用importlib.reload()重新加载扩展模块将继续

由于共享库加载受到限制(POSIX上的dlopen和Windows上的
LoadModuleEx都没有作用,除非重新设置
导入相关的属性。) ,通常无法在磁盘上更改
修改后的库后对其进行加载。


除了尝试使用新版本的
之外,其他重新加载的用例模块太少了,无法要求所有模块作者都在
的心中保持重新加载。如果需要类似重载的功能,则作者可以为此导出
专用功能。


代码更改


即使Python 3.4也不支持从更改后的文件中真正重载扩展模块。与它最接近的是保存副本的代码复制内容重新加载到模块的实际字典中。该代码仍然 存在,但是它不再因重新加载而触发,我不知道是否打算重新加载。我认为该代码目前仅用于子解释器。


I'm looking into these two related questions: here and here.

I am seeing a behavior I do not expect in Python 3.6, which differs from behavior using plain reload in Python 2.7 (and 3.4). Namely, it seems that a module attribute that would be populated during module initialization or when re-exec-ing the module during a reload, is not restored after its local name is removed with del ... see below:

For 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'

For Python 2.7 (and 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>

I have tried chasing the details of importlib from the source code down to the C-level module exec function, and I can't see any logic that would cause it to fail to write the re-initialized cos attribute back into the module's dict of module-scope globals.

My suspicion is that it's some type of bug in the C-level re-execution logic that looks at the attribute names found in the module's dictionary (the one that exists from whenever it was previously imported, and may be mutated to have deleted an attribute, like in my example), and then when using exec to write the module's execution side-effects into that dictionary, it's skipping key names (like cos) that don't exist in the module's namespace, which is different from the Python 2.7 behavior.

解决方案

I believe this is an (intended? unintended?) effect of PEP 489, an overhaul of extension module initialization. The PEP includes the following section:

Module Reloading

Reloading an extension module using importlib.reload() will continue to have no effect, except re-setting import-related attributes.

Due to limitations in shared library loading (both dlopen on POSIX and LoadModuleEx on Windows), it is not generally possible to load a modified library after it has changed on disk.

Use cases for reloading other than trying out a new version of the module are too rare to require all module authors to keep reloading in mind. If reload-like functionality is needed, authors can export a dedicated function for it.

The code change that appears to be responsible for this behavior was introduced in the commit that implemented PEP 489.

Even Python 3.4 didn't support truly reloading an extension module from a changed file; the closest it had was code to save a copy of the module's dict after initialization and copy the contents back into the module's actual dict on a reload. That code still exists, but it is no longer triggered for reloads, and I don't know if it was ever intended to be triggered for reloads. I believe that code is currently only used for subinterpreters.

这篇关于importlib.reload是否应该在Python 3.6中恢复已删除的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆