3

Yes: I know that we shouldn't be using global variables in Python but I'm trying to understand this behavior.

I have this file called bug.py :

x = 0


def foo():
    global x
    x = 100


if __name__ == '__main__':
    foo()
    print(x)

when I execute this as a file I get the expected result of a 100, see below.

(mani) franz@ubuntu:~/dropboxpython/poolparty$ python bug.py
100

However, when I do the same thing in the repl, x doesn't turn 100, see below

(mani) franz@ubuntu:~/dropboxpython/poolparty$ python
Python 3.6.4 | packaged by conda-forge | (default, Dec 23 2017, 16:31:06) 
[GCC 4.8.2 20140120 (Red Hat 4.8.2-15)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from bug import *
>>> x
0
>>> foo()
>>> x
0

Why does this happen?

2 Answers2

3

Let's recap what is the from module import something statement doing:

a reference to that value is stored in the local namespace, using the name in the as clause if it is present, otherwise using the attribute name

I'd like to add also that module is imported (i.e. added to sys.modules), but the name module is not created.

The second important point is that integers are immutable. Immutable objects behave like this, because each value is a separate object:

a = 0 # a-->0
b = a # a-->0<--b
a = 3 # 3<--a 0<--b; new object int(3) is created; b is still 0

So what is happeing is the import creates a local x initialized to x from bug which is zero. Calling foo() changes x in the bug module, but as shown above, it cannot affect the local x.


Try this to see the difference between immutable x and mutable y:

x = 0
y = [0]

def foo():
    global x, y
    x = 100
    y[0] = 100

if __name__ == '__main__':
    foo()
    print(x)
    print(y)
>>> from bug import *
>>> x, y
(0, [0])
>>> foo()
>>> x, y
(0, [100])
>>> 

UPDATE: checking the x set by foo.

>>> import sys
>>> sys.modules['bug'].x
100
VPfB
  • 14,927
  • 6
  • 41
  • 75
1

Globals in Python are global to a module, not across all modules. If you want to use x from the module bug then use it by importing bug module like below.

>>> import bug
>>> bug.x
0
>>> bug.foo()
>>> bug.x
100
>>> 

Don't use a from bug import *. This will create a new variable x initialized to whatever bug.x referred to at the time of the import. If you assign x=50 in bug.py file then you will get 50 after executing statement from bug import * like below.

>>> from bug import *
>>> x
50
>>> 

This new variable x would not be affected by assignments from the method foo(). This is the reason second time it won't gives you value 100 of variable x.

I tried to simplify it. Hope this will help :)

PyMaster
  • 1,094
  • 7
  • 11