34

first.py

myGlobal = "hello"

def changeGlobal():
   myGlobal="bye"

second.py

from first import *

changeGlobal()
print myGlobal

The output I get is

hello

although I thought it should be

bye

Why doesn't the global variable myGlobal changes after the call to the changeGlobal() function?

serv-inc
  • 35,772
  • 9
  • 166
  • 188
Joel
  • 5,949
  • 12
  • 42
  • 58

3 Answers3

21

Try:

def changeGlobal():
    global myGlobal
    myGlobal = "bye"

Actually, that doesn't work either. When you import *, you create a new local module global myGlobal that is immune to the change you intend (as long as you're not mutating the variable, see below). You can use this instead:

import nice

nice.changeGlobal()
print nice.myGlobal

Or:

myGlobal = "hello"

def changeGlobal():
   global myGlobal
   myGlobal="bye"

changeGlobal()

However, if your global is a mutable container, you're now holding a reference to a mutable and are able to see changes done to it:

myGlobal = ["hello"]

def changeGlobal():
    myGlobal[0] = "bye"
TryPyPy
  • 6,214
  • 5
  • 35
  • 63
  • 1
    I forgot to mention in my orignal post that i tried it with global and it didnt work. I was not aware that when importing with * I create a new local var. Thanks! – Joel Jan 16 '11 at 17:41
  • 6
    It's not quite correct to say that you create a new local. You're actually creating a new global in the second module. Each module has its own set of globals. – Brian Goldman Jan 16 '11 at 19:25
  • `import nice` is the best option there, however how do i import folder with absolute path as package like `import app.base.admin.crud as cx` https://stackoverflow.com/questions/48098231/python-how-do-i-import-folder-with-absolute-path-as-package – TomSawyer Jan 04 '18 at 16:05
8

I had once the same concern as yours and reading the following section from Norman Matloff's Quick and Painless Python Tutorial was really a good help. Here is what you need to understand (copied from Matloff's book):

Python does not truly allow global variables in the sense that C/C++ do. An imported Python module will not have direct access to the globals in the module which imports it, nor vice versa.

For instance, consider these two files, x.py,

# x.py
import y
def f():
  global x
  x = 6
def main():
  global x
  x = 3
f()
y.g()
if __name__ == ’__main__’:
  main()

and y.py:

# y.py
def g():
  global x
  x += 1

The variable x in x.py is visible throughout the module x.py, but not in y.py. In fact, execution of the line x += 1

in the latter will cause an error message to appear, “global name ’x’ is not defined.”

Indeed, a global variable in a module is merely an attribute (i.e. a member entity) of that module, similar to a class variable’s role within a class. When module B is imported by module A, B’s namespace is copied to A’s. If module B has a global variable X, then module A will create a variable of that name, whose initial value is whatever module B had for its variable of that name at the time of importing. But changes to X in one of the modules will NOT be reflected in the other.

Say X does change in B, but we want code in A to be able to get the latest value of X in B. We can do that by including a function, say named GetX() in B. Assuming that A imported everything from B, then A will get a function GetX() which is a copy of B’s function of that name, and whose sole purpose is to return the value of X. Unless B changes that function (which is possible, e.g. functions may be assigned), the functions in the two modules will always be the same, and thus A can use its function to get the value of X in B.

wassimans
  • 8,382
  • 10
  • 47
  • 58
  • 1
    Thanks, python GLOBAL VARIABLES ARE NOT GLOBAL, they are module attributes -- many people fall prey to this 'bug'. Now, if you: 'from foo import *' is there a 'foo' module that might have 'globals' from foo? or is it that everthing in foo now gets merged into the 'current module'? – Ribo Aug 11 '16 at 13:51
  • My testing contradicts your statement that 'When module B is imported'... that module Bs name space is copied into the current namespace (ie module A's) When I invoke python from the command line (ie not in module A) and import a module, the 'globals' of the imported module do not appear (to be copied) into the current namespace. The name of the imported module is in the namespace (globals()), and moduleName.itsGlobalVar is defined in it, but itsGlobalVar is not in globals() – Ribo Aug 11 '16 at 14:33
2

Python global variables are not global

As wassimans points out above they are essentially attributes within the scope of the module they are defined in (or the module that contains the function that defined them).

The first confusion(bug) people run into is not realizing that functions have a local name space and that setting a variable in a function makes it a local to the function even when they intended for it to change a (global) variable of the same name in the enclosing module. (declaring the name in a 'global' statement in the function, or accessing the (global) variable before setting it.)

The second confusion(bug) people run into is that each module (ie imported file) contains its own so called 'global' name space. I guess python things the world(globe) is the module -- perhaps we are looking for 'universal' variables that span more than one globe.

The third confusion (that I'm starting to understand now) is where are the 'globals' in the __main__ module? Ie if you start python from the command line in interactive mode, or if you invoke python script (type the name of the foo.py from the command shell) -- there is no import of a module whose name you can use.

The contents of 'globals()' or globals().keys() -- which gives you a list of the globals -- seems to be accessible as: dir(sys.modules['__main__']) It seems that the module for the loaded python script (or the interactive session with no loaded script), the one named in: __name__, has no global name, but is accessible as the module whose name is '__main__' in the system's list of all active modules, sys.modules

Ribo
  • 3,363
  • 1
  • 29
  • 35
  • @Andrew what didn't work? What did it do when you did what you did? – Ribo Aug 13 '17 at 18:28
  • sys.modules['main'] – Andrew Aug 13 '17 at 18:46
  • 1
    Oh! the text formatter interpreted the double underscores as 'make this italic'. I 'escaped' the double underscores around __name__ and __main__ so they show correctly. Also, it seems to need dir() rather than .keys() – Ribo Aug 13 '17 at 23:20
  • Awesome, it's working now, this is perfect, thanks! All one has to do is put e.g.: `g = sys.modules['__main__']` at the top of an imported file and they can then access `g.whatever`. – Andrew Aug 14 '17 at 12:39