pythonglobal

Python global variables in shared modules


I am trying to understand the behavior of variables shared across modules. My impression was a global variable in one module could be accessed in another, and sometimes this seems to be what happens, but sometimes it is not. (I recognize global variables are usually not the right tool, but there are situations where their use is appropriate.)

Here is a code example to illustrate my confusion:

shared.py

globalvar=0                 # a global scalar variable
globalarray1=[1,2,3]        # a global array modified by .append()
globalarray2=['A','B','C']  # a global array modified by reassignment

def set_globals():
    global globalvar
    global globalarray1
    global globalarray2

    globalvar=1
    globalarray1.append(4)
    globalarray2=['a','b','c']

    print("set_globals: globalvar="+str(globalvar))
    print("set_globals: globalarray1="+str(globalarray1))
    print("set_globals: globalarray2="+str(globalarray2))

module.py

from paas.shared import *

def _main_():
    global globalvar
    global globalarray1
    global globalarray2

    set_globals()

    print("main: globalvar="+str(globalvar))
    print("main: globalarray1="+str(globalarray1))
    print("main: globalarray2="+str(globalarray2))

_main_()

When I run the program, I get the following output:

set_globals: globalvar=1
set_globals: globalarray1=[1, 2, 3, 4]
set_globals: globalarray2=['a', 'b', 'c']
main: globalvar=0
main: globalarray1=[1, 2, 3, 4]
main: globalarray2=['A', 'B', 'C']

So

Can someone explain what is going on? I have only seen fairly simple tutorial-type documentation about global variables; if there is documentation that describes what is happening here I would appreciate a pointer.

ADDED NOTE: This is not related to the way a local variable in a function hides a global variable with the same name; those are two different variables with the same name and different initial values. It does appear that the import creates a new module variable with the same name, but it starts with the initial value of the variable of the same name from the imported module.


Solution

  • What you're observing stems from Python's behavior with respect to variables, imports, and mutability. Let's break it down:

    1. Shared Mutable Objects (Lists in this case):
    1. Reassigning Variables:
    1. Python's Import Mechanism:

    How to fix this and see consistent behavior:

    You should access variables from the shared module using an explicit module prefix. This way, you're always referring to the most recent value of the variable in the shared module. Here's how you can change your module.py, let's call it module2.py:

    import paas.shared as shared
    
    def _main_():
        shared.set_globals()
    
        print("main: globalvar="+str(shared.globalvar))
        print("main: globalarray1="+str(shared.globalarray1))
        print("main: globalarray2="+str(shared.globalarray2))
    
    _main_()
    

    With this change, the print statements in _main_() will refer directly to the shared module's versions of the variables, and you'll see consistent behavior between set_globals and _main_().

    Now let's compare the output. Here's module.py (unmodified from above):

    $ python module.py
    
       set_globals: globalvar=1
       set_globals: globalarray1=[1, 2, 3, 4]
       set_globals: globalarray2=['a', 'b', 'c']
       main: globalvar=0
       main: globalarray1=[1, 2, 3, 4]
       main: globalarray2=['A', 'B', 'C']
    

    And now the new code using an explicit import (module2.py):

    $ python module2.py  
                            
       set_globals: globalvar=1
       set_globals: globalarray1=[1, 2, 3, 4]
       set_globals: globalarray2=['a', 'b', 'c']
       main: globalvar=1
       main: globalarray1=[1, 2, 3, 4]
       main: globalarray2=['a', 'b', 'c']