escitalopram
escitalopram

Reputation: 3856

Python global variables don't seem to work across modules

Code

I'd like to use a global variable in other modules with having changes to its value "propagated" to the other modules.

a.py:

x="fail"
def changeX():
    global x
    x="ok"

b.py:

from a import x, changeX
changeX()
print x

If I run b.py, I'd want it to print "ok", but it really prints "fail".

Questions

  1. Why is that?
  2. How can I make it print "ok" instead?

(Running python-2.7)

Upvotes: 11

Views: 3863

Answers (3)

chtenb
chtenb

Reputation: 16184

You can also add another import statement after changeX. This would turn the code from b.py into

from a import x, changeX
changeX()
from a import x
print x

This illustrates that by calling changeX, only x in module a is changed. Importing it again, binds the updated value again to the identifier x.

Upvotes: 3

Bunyk
Bunyk

Reputation: 8067

Also you can use mutable container, for example list:

a.py

x = ['fail']

def changeX():
    x[0] = 'ok'

b.py

from a import changeX, x

changeX()
print x[0]

Upvotes: 2

user4815162342
user4815162342

Reputation: 154866

In short: you can't make it print "ok" without modifying the code.

from a import x, changeX is equivalent to:

import a
x = a.x
changeX = a.changeX

In other words, from a import x doesn't create an x that indirects to a.x, it creates a new global variable x in the b module with the current value of a.x. From that it follows that later changes to a.x do not affect b.x.

To make your code work as intended, simply change the code in b.py to import a:

import a
a.changeX()
print a.x

You will have less cluttered imports, easier to read code (because it's clear what identifier comes from where without looking at the list of imports), less problems with circular imports (because not all identifiers are needed at once), and a better chance for tools like reload to work.

Upvotes: 15

Related Questions