pythonimportmodule

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

  • 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.