I created a Python module with a single function that just prints 'a!'. I opened up the Python interpreter and imported the module in 2 different syntaxes
>>> import a
>>> from a import func
>>> func()
a!
>>> a.func()
a!
At this point I changed func to print something else, then evaluates again
>>> func()
a!
>>> a.func()
a!
This is expected of course as the module was not reloaded. Then I reloaded the module and expected both functions to update, however:
>>> reload(a)
<module 'a' from 'a.py'>
>>> a.func()
aasd!
>>> func()
a!
Only a.func seems to update. I always thought that Python keeps only a single instance of the same module, but now there appears to be two. I did further testing in order to verify my claim, and added a print statement at top level of the module, then restarted the interpreter and imported again:
>>> import a
module imported
>>> import a
>>> from a import func
This confuses me even more as I expected to see 'module imported' twice. The third experiment that I did was the global variable experiment:
>>> import a
module imported
>>> from a import GLOBAL_VAR
>>> GLOBAL_VAR = 5
>>> a.GLOBAL_VAR
1
>>> GLOBAL_VAR
5
>>> GLOBAL_VAR is a.GLOBAL_VAR
False
So there's a single instance of the module, but different instances of the objects inside? How is it possible to implement Gevent's monkey patching with such behaviour?
A module, once it's imported, is just another python object. So seeing the following example, your results should not surprise you at all:
x = SomeObject()
x.y = 1
a = x.y
x.y = 2
print(a) #a is still 1, not 2
When you do from module import name
, a variable name
is created in the current namespace which holds a reference to the imported thing (be it a package/module/class/whatever). It's syntactic sugar for the following:
import module
name = module.name
Now, when you reload module
, you obviously don't update the reference name
holds.
Concerning your second experiment, a module is cached in sys.modules
after the import; subsequent imports will take advantage of the cache. Thus all code that is directly at the module level, like your print
, will only get executed on the first import.
When you reload a module, all the functions in that are reloaded in the current module. But when you import a specific function from a module, it becomes local to the current module. So, changing one will not affect the other.
Check this out:
import math
from math import factorial
print locals()
print id(math.factorial), id(factorial)
math.factorial, factorial = 0, 1
print id(math.factorial), id(factorial)
reload(math)
print id(math.factorial), id(factorial)
from math import factorial
print id(math.factorial), id(factorial)
Output
{'__builtins__': <module '__builtin__' (built-in)>,
'__file__': '/home/thefourtheye/Desktop/Test.py',
'__package__': None,
'factorial': <built-in function factorial>, # Factorial is in the local context
'__name__': '__main__',
'__doc__': None,
'math': <module 'math' (built-in)>}
39346504 39346504
33545712 33545688
39346504 33545688
39346504 39346504
id
prints the address of the object in memory in CPython implementation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With