How to share global variable with lazy initialization?

Viewed 728

Probably a very n00bish question but gets me every time...

Can someone explain to me why the following prints "None"?

test1.py

test = None

def init():
    global test
    test = 1

test2.py

from test1 import test, init

# test1.test should be getting a value here
init()
# I expect test to be a reference to test1.test 
# but behaves like a copy on import-time ?!
print(test)
2 Answers

By doing test = 1 you are changing the reference of test, but the previous reference (to None) has already been imported in test2.py. If you want to keep it you can, for example, use an object:

# test1.py
test = {}

def init():
    # you do not need `global` since you are not rewriting the variable
    test['x'] = 1
# test2.py
from test1 import init, test

assert test == {}
init()
assert test['x'] == 1  # works

When you use from test1 import test you create a variable in your local scope which is bound to the value of test1.test. Assigning a value to test would then replace it with the new value but the original test1.test would remain the same. So in your case when you call init() in test2.py it actually takes the test1.test variable instead of the one in your local scope.

>>> import test1
>>> from test1 import test, init

>>> init()
>>> print(test)
None
>>> print(test1.test)
1

Note that as michaeldel wrote in his response the situation is different when you use a mutable data type (like list or dict) as modifying it would indeed affect the original variable. My answer is based on ThiefMaster's answer on a similar question. You can check it out for more detailed explanation.

Related