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.