After several years of regular Python use, I really admire that things work how I expect about 90% of the time. To be fair, the other 10% is typically user error. It is easy to overlook nuances in a language, even if you should know better.
I ran into this gotcha in Python recently: when importing a global variable from a module explicitly by name, that variable will be bound to the local namespace. If that bound global is of immutable type (such as the built-in integer type), changes to that variable will not be reflected in the original namespace. Whew, that was an exhausting explanation, an example demonstrates the issue nicely.
Consider the following three Python files, mymod.py
, main1.py
, and main2.py
:
mymod.py
foo = 10
def func():
print "info5:", foo
Our example module (mymod.py
) defines a global variable and function that uses that global.
main1.py
from mymod import foo, func
_ = None; print "info1:", [_ for _ in globals() if not _.startswith("_")]
print "info2:", foo, id(foo)
func()
foo += 1
print "info3:", foo, id(foo)
func()
Our first example of using mymod
imports the global and function by name. The global is updated by main1.py
and then the function is called. However, because the imported foo
was updated, it no longer points to the same object as foo
in the mymod
namespace. The output of this script is the following:
info1: ['func', 'foo']
info2: 10 11159084
info5: 10 11159084
info3: 11 11159072
info5: 10 11159084
main2.py
import mymod
_ = None; print "info1:", [_ for _ in globals() if not _.startswith("_")]
print "info2:", mymod.foo, id(mymod.foo)
mymod.func()
mymod.foo += 1
print "info3:", mymod.foo, id(mymod.foo)
mymod.func()
Our second example of using mymod
imports only the module. Since the foo
global is updated and accessed via the mymod
namespace, the changes will be reflected both in main2
and mymod
. The output of this script is the following:
info1: ['mymod']
info2: 10 32982572
info5: 10 32982572
info3: 11 32982560
info5: 11 32982560
Please note that this gotcha only applies if the global variable is of immutable type. If the variable is mutable, such as a list or dictionary, this particular issue would not be expressed.