Suppose I have a package named bar, and it contains bar.py:
a = None
def foobar():
print a
and __init__.py:
from bar import a, foobar
Then I execute this script:
import bar
print bar.a
bar.a = 1
print bar.a
bar.foobar()
Here’s what I expect:
None
1
1
Here’s what I get:
None
1
None
Can anyone explain my misconception?
You are using
from bar import a.abecomes a symbol in the global scope of the importing module (or whatever scope the import statement occurs in).When you assign a new value to
a, you are just changing which valueapoints too, not the actual value. Try to importbar.pydirectly withimport barin__init__.pyand conduct your experiment there by settingbar.a = 1. This way, you will actually be modifyingbar.__dict__['a']which is the ‘real’ value ofain this context.It’s a little convoluted with three layers but
bar.a = 1changes the value ofain the module calledbarthat is actually derived from__init__.py. It does not change the value ofathatfoobarsees becausefoobarlives in the actual filebar.py. You could setbar.bar.aif you wanted to change that.This is one of the dangers of using the
from foo import barform of theimportstatement: it splitsbarinto two symbols, one visible globally from withinfoowhich starts off pointing to the original value and a different symbol visible in the scope where theimportstatement is executed. Changing a where a symbol points doesn’t change the value that it pointed too.This sort of stuff is a killer when trying to
reloada module from the interactive interpreter.