The global keyword
A function can read a global variable. But as soon as a function assigns to a name, that name is a local variable of the function, even when a global variable of the same name exists:
score = 0
def add_points(points):
score = points
print("Inside:", score)
add_points(5)
print("Outside:", score)
Inside: 5
Outside: 0The assignment created a new local score. The global score is still 0.
Python decides this for the whole function before it runs it: a name the function assigns to anywhere in it is local everywhere in it. That's why this function fails, although it looks as if it simply adds to the global variable:
score = 0
def add_points(points):
score += points
add_points(5)
print(score)
Traceback (most recent call last):
File "main.py", line 8, in <module>
add_points(5)
~~~~~~~~~~^^^
File "main.py", line 5, in add_points
score += points
^^^^^
UnboundLocalError: cannot access local variable 'score' where it is not associated with a valuescore += points is short for score = score + points, which is an assignment, so score is local in add_points. To work out the new value, Python first reads the local score, which has no value yet: an UnboundLocalError.
global
The statement global at the start of a function says that a name means the global variable. Then assigning to it changes the global variable:
lives = 3
def lose_life():
global lives
lives -= 1
print("Ouch! Lives left:", lives)
lose_life()
lose_life()
if lives > 0:
print("Still in the game")
Ouch! Lives left: 2
Ouch! Lives left: 1
Still in the gameglobal is only needed to assign to a global variable. Reading one needs nothing, and neither does changing the contents of a global list with a method such as append, because that doesn't assign to the variable.
When to use it, and when not
Use global sparingly. A function that changes global variables can't be understood on its own: to know what it does, you need to know what the rest of the program does to the same variables, and it can't be reused in another program without them. Above all, global is not a way to get a result out of a function:
def average(numbers):
global result
result = sum(numbers) / len(numbers)
This works, but return sum(numbers) / len(numbers) is better: the caller decides where the result goes, and the function works the same wherever it's used.
Global variables are reasonable for a few things that really belong to the whole program: the state of a game, such as the lives left above, or a counter of how many times something has happened in the program.