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
. a
becomes 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 value a
points too, not the actual value. Try to import bar.py
directly with import bar
in __init__.py
and conduct your experiment there by setting bar.a = 1
. This way, you will actually be modifying bar.__dict__['a']
which is the 'real' value of a
in this context.
It's a little convoluted with three layers but bar.a = 1
changes the value of a
in the module called bar
that is actually derived from __init__.py
. It does not change the value of a
that foobar
sees because foobar
lives in the actual file bar.py
. You could set bar.bar.a
if you wanted to change that.
This is one of the dangers of using the from foo import bar
form of the import
statement: it splits bar
into two symbols, one visible globally from within foo
which starts off pointing to the original value and a different symbol visible in the scope where the import
statement 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 reload
a module from the interactive interpreter.