How to change a module variable from another module?
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?
Solution 1:
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.
Solution 2:
One source of difficulty with this question is that you have a program named bar/bar.py
: import bar
imports either bar/__init__.py
or bar/bar.py
, depending on where it is done, which makes it a little cumbersome to track which a
is bar.a
.
Here is how it works:
The key to understanding what happens is to realize that in your __init__.py
,
from bar import a
in effect does something like
a = bar.a
# … where bar = bar/bar.py (as if bar were imported locally from __init__.py)
and defines a new variable (bar/__init__.py:a
, if you wish). Thus, your from bar import a
in __init__.py
binds name bar/__init__.py:a
to the original bar.py:a
object (None
). This is why you can do from bar import a as a2
in __init__.py
: in this case, it is clear that you have both bar/bar.py:a
and a distinct variable name bar/__init__.py:a2
(in your case, the names of the two variables just happen to both be a
, but they still live in different namespaces: in __init__.py
, they are bar.a
and a
).
Now, when you do
import bar
print bar.a
you are accessing variable bar/__init__.py:a
(since import bar
imports your bar/__init__.py
). This is the variable you modify (to 1). You are not touching the contents of variable bar/bar.py:a
. So when you subsequently do
bar.foobar()
you call bar/bar.py:foobar()
, which accesses variable a
from bar/bar.py
, which is still None
(when foobar()
is defined, it binds variable names once and for all, so the a
in bar.py
is bar.py:a
, not any other a
variable defined in another module—as there might be many a
variables in all the imported modules). Hence the last None
output.
Conclusion: it is best to avoid any ambiguity in import bar
, by not having any bar/bar.py
module (since bar.__init__.py
makes directory bar/
a package already, that you can also import with import bar
).