How to change a module variable from another module?
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.
To put another way: Turns out this misconception is very easy to make. It is sneakily defined in the Python language reference: the use of object instead of symbol. I would suggest that the Python language reference make this more clear and less sparse..
The
from
form does not bind the module name: it goes through the list of identifiers, looks each one of them up in the module found in step (1), and binds the name in the local namespace to the object thus found.
HOWEVER:
When you import, you import the current value of the imported symbol and add it to your namespace as defined. You are not importing a reference, you are effectively importing a value.
Thus, to get the updated value of i
, you must import a variable that holds a reference to that symbol.
In other words, importing is NOT like an import
in JAVA, external
declaration in C/C++ or even a use
clause in PERL.
Rather, the following statement in Python:
from some_other_module import a as x
is more like the following code in K&R C:
extern int a; /* import from the EXTERN file */
int x = a;
(caveat: in the Python case, "a" and "x" are essentially a reference to the actual value: you're not copying the INT, you're copying the reference address)
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
).