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?
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..
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 ause
clause in PERL.Rather, the following statement in Python:
is more like the following code in K&R C:
(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 eitherbar/__init__.py
orbar/bar.py
, depending on where it is done, which makes it a little cumbersome to track whicha
isbar.a
.Here is how it works:
The key to understanding what happens is to realize that in your
__init__.py
,in effect does something like
and defines a new variable (
bar/__init__.py:a
, if you wish). Thus, yourfrom bar import a
in__init__.py
binds namebar/__init__.py:a
to the originalbar.py:a
object (None
). This is why you can dofrom bar import a as a2
in__init__.py
: in this case, it is clear that you have bothbar/bar.py:a
and a distinct variable namebar/__init__.py:a2
(in your case, the names of the two variables just happen to both bea
, but they still live in different namespaces: in__init__.py
, they arebar.a
anda
).Now, when you do
you are accessing variable
bar/__init__.py:a
(sinceimport bar
imports yourbar/__init__.py
). This is the variable you modify (to 1). You are not touching the contents of variablebar/bar.py:a
. So when you subsequently doyou call
bar/bar.py:foobar()
, which accesses variablea
frombar/bar.py
, which is stillNone
(whenfoobar()
is defined, it binds variable names once and for all, so thea
inbar.py
isbar.py:a
, not any othera
variable defined in another module—as there might be manya
variables in all the imported modules). Hence the lastNone
output.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). So when you assign a new value toa
, you just change which valuea
points too, not the actual value. try to importbar.py
directly withimport bar
in__init__.py
and conduct your experiment there by settingbar.a = 1
. This way, you are actually modifyingbar.__dict__['a']
which is the 'real' value ofa
in this context.It's a little convoluted with three layers but
bar.a = 1
changes the value ofa
in the module calledbar
that is actually derived from__init__.py
. It does not change the value ofa
thatfoobar
sees becausefoobar
lives in the actual filebar.py
. You could setbar.bar.a
if you wanted to change that.This is one of the dangers of using the
from foo import bar
form of theimport
statement: it splitsbar
into two symbols, one visible globally from withinfoo
which starts off pointing to the original value and a different symbol visible in the scope where theimport
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.