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 lan开发者_StackOverflow社区guage 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'
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.
A better way to do tasks like this, is to declare variables in the same module you want to change them in. In this case in b
. Then import b
inside a
, and you can do what ever you want.You can use the variables unchanged, just like you have declared them in a
, or you can change them. Look at this:
b.py
test1 = 'a'
test2 = None
test3 = '3'
def changeVars():
global test1,test2,test3
test1 = 'NEW VAR 1'
test2 = 'NEW VAR 2'
test3 = 'NEW VAR 3'
print test1, test2, test3 #prints 'NEW VAR 1', 'NEW VAR 2', 'NEW VAR 3'
a.py
import b
if __name__ == '__main__':
print b.test1, b.test2, b.test3 #prints 'a', None, 3
b.changeVars()
print b.test1, b.test2, b.test3 #prints 'NEW VAR 1', 'NEW VAR 2', 'NEW VAR 3'
Note: There is no need for circular imports in this case; and circular import is causing your problems, because it doesn't behave like you thought it should. So, with just one import, you have all that you wanted to have with your code, and you can modify these variables values from within both modules.
精彩评论