Coder Perfect

Global variables in a Python function?

Problem

I know I should avoid using global variables in the first place because of issues like this, but is the following a valid method to utilize them if I do? (I’m trying to call a global duplicate of a variable that was generated in a different function.)

x = "somevalue"

def func_A ():
   global x
   # Do things to x
   return x

def func_B():
   x = func_A()
   # Do things
   return x

func_A()
func_B()

Does the global copy of x that func a uses and alters have the same value as the x that the second function uses? Is it important to invoke the functions in the same sequence as they were defined?

Asked by Akshat Shekhar

Solution #1

You can just use the name of a global variable to access it. To modify its value, however, you must use the global keyword.

E.g.

global someVar
someVar = 55

This would alter the global variable’s value to 55. If not, it will just assign 55 to a local variable.

The order in which function definition listings are listed doesn’t matter (as long as they don’t refer to each other), but the order in which they are called matters.

Answered by Levon

Solution #2

Unless a variable is stated earlier in the function as referring to a globally scoped variable with the keyword global, every assignment to a variable not already declared within that scope produces a new local variable.

To illustrate what happens, let’s look at a modified version of your pseudocode:

# Here, we're creating a variable 'x', in the __main__ scope.
x = 'None!'

def func_A():
  # The below declaration lets the function know that we
  #  mean the global 'x' when we refer to that variable, not
  #  any local one

  global x
  x = 'A'
  return x

def func_B():
  # Here, we are somewhat mislead.  We're actually involving two different
  #  variables named 'x'.  One is local to func_B, the other is global.

  # By calling func_A(), we do two things: we're reassigning the value
  #  of the GLOBAL x as part of func_A, and then taking that same value
  #  since it's returned by func_A, and assigning it to a LOCAL variable
  #  named 'x'.     
  x = func_A() # look at this as: x_local = func_A()

  # Here, we're assigning the value of 'B' to the LOCAL x.
  x = 'B' # look at this as: x_local = 'B'

  return x # look at this as: return x_local

In fact, you could rewrite all of func_B with the variable named x_local and it would work identically.

Only the sequence in which your functions perform operations that affect the value of the global x matters. Because func B invokes func A, the order doesn’t matter in our scenario. Order is important in this case:

def a():
  global foo
  foo = 'A'

def b():
  global foo
  foo = 'B'

b()
a()
print foo
# prints 'A' because a() was the last function to modify 'foo'.

It’s worth noting that global is only required when working with global objects. Without declaring global, you can still access them from within a function. As a result, we have:

x = 5

def access_only():
  return x
  # This returns whatever the global value of 'x' is

def modify():
  global x
  x = 'modified'
  return x
  # This function makes the global 'x' equal to 'modified', and then returns that value

def create_locally():
  x = 'local!'
  return x
  # This function creates a new local variable named 'x', and sets it as 'local',
  #  and returns that.  The global 'x' is untouched.

Note the difference between access only and create locally: access only accesses the global x while not calling global, and create locally, although not calling global, produces a local copy because it assigns a value.

The issue arises from the fact that global variables should not be used.

Answered by jdotjdot

Solution #3

When you want a function to be able to edit a global variable, as others have pointed out, you must declare the variable global in the function. You don’t require global if you merely wish to access it.

To clarify, “modify” means that if you want to re-bind the global name so that it points to a different object, the name must first be declared global in the function.

Because many actions that change (mutate) an object do not re-bind the global name to point to a different object, they are all acceptable even if the name global is not declared in the function.

d = {}
l = []
o = type("object", (object,), {})()

def valid():     # these are all valid without declaring any names global!
   d[0] = 1      # changes what's in d, but d still points to the same object
   d[0] += 1     # ditto
   d.clear()     # ditto! d is now empty but it`s still the same object!
   l.append(0)   # l is still the same list but has an additional member
   o.test = 1    # creating new attribute on o, but o is still the same object

Answered by kindall

Solution #4

Within a function, you can directly access a global variable. Use “global variable name” if you wish to update the value of that global variable. Consider the following scenario:

var = 1
def global_var_change():
      global var
      var = "value changed"
global_var_change() #call the function for changes
print var

This is not, in general, a good programming practise. Code might become difficult to comprehend and debug if namespace logic is broken.

Answered by Noisy_Botnet

Solution #5

Using a global as the default value of a parameter was one example that threw me off guard.

globVar = None    # initialize value of global variable

def func(param = globVar):   # use globVar as default value for param
    print 'param =', param, 'globVar =', globVar  # display values

def test():
    global globVar
    globVar = 42  # change value of global
    func()

test()
=========
output: param = None, globVar = 42

I had anticipated a value of 42 for param. Surprise. When Python 2.7 first parsed the function func, it assessed the value of globVar. The default value assigned to param was unaffected by changing the value of globVar. Delaying the evaluation, as seen below, worked perfectly for me.

def func(param = eval('globVar')):       # this seems to work
    print 'param =', param, 'globVar =', globVar  # display values

Alternatively, if you want to be safe,

def func(param = None)):
    if param == None:
        param = globVar
    print 'param =', param, 'globVar =', globVar  # display values

Answered by SoloPilot

Post is based on https://stackoverflow.com/questions/10588317/python-function-global-variables