2

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)
martineau
  • 119,623
  • 25
  • 170
  • 301
urban
  • 5,392
  • 3
  • 19
  • 45
  • It will work if you don't use a `from`. i.e. in test2.py just do an `import test1`, then refer to `test1.test`. – martineau Apr 11 '20 at 10:32
  • i am also curious on this but should test change when init call and test declared , but test value should change – sahasrara62 Apr 11 '20 at 10:37

2 Answers2

2

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
michaeldel
  • 2,204
  • 1
  • 13
  • 19
  • I assume the question becomes why assignment changes the reference (but maybe this is even more n00bish q :) ) – urban Apr 11 '20 at 10:30
  • 1
    That is the way Python works, every variable is simply a name to designate an object in memory. Assignment means you make that name designate something else, but other variables that were already pointing to the same previous object remain unchanged. – michaeldel Apr 11 '20 at 10:37
2

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.

Jan Koci
  • 315
  • 3
  • 11