Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I change another modules variable in python?

I'm trying to allow a second module to modify the variables of the first in a circular import, but it doesn't seem to work.

I have 2 questions: 1) Why doesn't this work / what is the reasoning for this from a language development perspective and 2) are there any easy solutions that allow me to do the same thing perhaps in a slightly different way?

a.py:

import b

test1 = 'a'
test2 = None
test3 = '3'

if __name__ == '__main__':
  print test1, test2, test3 #prints 'a', None, 3
  b.changeVars()
  print test1, test2, test3 #prints 'a', None, 3 (i.e. nothing has changed)

b.py:

import a

def changeVars():
  print a.test1, a.test2, a.test3 #prints 'a', None, 3
  a.test1 = 'NEW VAR 1'
  a.test2 = 'NEW VAR 2'
  a.test3 = 'NEW VAR 3'

  print a.test1, a.test2, a.test3 #prints 'NEW VAR 1', 'NEW VAR 2', 'NEW VAR 3'
like image 884
Bill Zimmerman Avatar asked Jan 22 '23 00:01

Bill Zimmerman


1 Answers

What's happening is that when b.py tries to import a, there isn't an entry for it in sys.modules because the entry is under __main__. This causes the import mechanisms to re-import the module and place it under the name a. So now there is an a module and an entirely unrelated __main__ module. Changing b.py to something like this does the trick.

import sys
a = sys.modules['__main__']

def changeVars():
  print a.test1, a.test2, a.test3 #prints 'a', None, 3
  a.test1 = 'NEW VAR 1'
  a.test2 = 'NEW VAR 2'
  a.test3 = 'NEW VAR 3'

  print a.test1, a.test2, a.test3 #prints 'NEW VAR 1', 'NEW VAR 2', 'NEW VAR 3'

yields

aaron@aaron-laptop:~/code/tmp$ python a.py
a None 3
a None 3
NEW VAR 1 NEW VAR 2 NEW VAR 3
NEW VAR 1 NEW VAR 2 NEW VAR 3
aaron@aaron-laptop:~/code/tmp$ 

To get a better example of what's going on, consider these files:

#a.py
import b
import a

test = 'Foo'   

if __name__ == '__main__':
  print test  #prints 'Foo'
  b.changeVars()
  print a.test, test # prints 'Foo', 'Bar'

and

#b.py
import a as a1

import sys
a2 = sys.modules['__main__']

def changeVars():

  print a1.test, a2.test # Prints 'Foo', 'Foo'
  a2.test = 'Bar'
  print a1.test, a2.test # Prints 'Foo', 'Bar'

Which outputs

Foo
Foo Foo
Foo Bar
Foo Bar

This is clearly showing that sys.modules['a'] and sys.modules['__main__'] are referring to two different objects. The solution is probably to put the following as the first lines of a.py

import __main__ as a  # due to Ignacio Vazquez-Abrams 

Doing it this way allows for any other module to import a as well. On the whole though, I really don't see why you would want to do this. There's probably a better way to get this done.

like image 56
aaronasterling Avatar answered Feb 03 '23 21:02

aaronasterling