The global keyword

Published

2024-02-04

Python provides a keyword, global, which is often misunderstood and misused. Some folks seem to believe that this use of this keyword is necessary if we wish to use the value of a variable defined in the outer scope within a function. Not quite!

Consider the common case of having some constant which might be used in many computations. We’d like to have such a constant defined once, and never changed, but available wherever we might need it.

Unlike many other languages, Python does not have a const keyword that enforces that a value remain constant. In Python, that’s down to you, the programmer.

Here’s an example:

import math

g_0 = 9.806  # std. accel. due to gravity

def calc_period(l_):
    return 2 * math.pi * math.sqrt(l_ / g_0)


length = float(input("Enter length of pendulum (m): "))
period = calc_period(length)
print(f"The period of your pendulum is {period:.2f} s.")

This works just fine. If the user were to enter 10 for the length of the pendulum, it would print

The period of your pendulum is 6.35 s.

as you’d expect. Notice we did not use the global keyword, even though we’re using g_0 within our function. Why does this work? It works because if Python encounters an identifier within the body of a function which is not either the name of a formal parameter or a variable created within the body of the function, it will look in the nearest enclosing scope for a matching identifier. This kind of variable is called a free variable. So in this case, within the body of the function g_0 is a free variable. It is defined in the outer scope, so Python finds it there, and uses it in the calculation.

On occasion, I’ve seen code that looks like this:

import math

g_0 = 9.806  # std. accel. due to gravity

def calc_period(l_):
    global g_0  # Notice this line here
    return 2 * math.pi * math.sqrt(l_ / g_0)


length = float(input("Enter length of pendulum (m): "))
period = calc_period(length)
print(f"The period of your pendulum is {period:.2f} s.")

It seems that in cases like this the programmer believes that the global keyword is telling Python to use g_0 from the outer scope. But we saw in the previous example that this is not necessary!

So what does the global keyword do?

Here’s an excerpt from the official Python documentation:

“The global statement is a declaration which holds for the entire current code block. It means that the listed identifiers are to be interpreted as globals. It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global.”1

So the global keyword allows the programmer to modify the value of a variable defined in the outer scope within the body of the function—and this is quite often not what is intended at all.

Consider the following example.

import math

g_0 = 9.806  # std. accel. due to gravity

def calc_period(l_):
    global g_0  # Notice this line here
    p = 2 * math.pi * math.sqrt(l_ / g_0)
    g_0 = 400  # This is an error
    return p


length = float(input("Enter length of pendulum (m): "))
period = calc_period(length)
print(f"The period of your pendulum is {period:.2f} s.")

# Now perform exactly the same computation, with the same input.
period = calc_period(length)
print(f"The period of your pendulum is {period:.2f} s.")

If the user enters 10 at the prompt, this program will print

The period of your pendulum is 6.35 s.
The period of your pendulum is 0.99 s.

Why? Because the inappropriate use of global allowed the programmer to modify g_0 within the function! So when the function was called a second time, a g_0 had a different value.

Here, the use of global permitted a change to what should have been a constant! Yikes!

Let’s see what would happen if we removed the global statement.

import math

g_0 = 9.806  # std. accel. due to gravity

def calc_period(l_):
    p = 2 * math.pi * math.sqrt(l_ / g_0)
    g_0 = 400  # This creates a new, local g_0, 
    # without changing g_0 in the outer scope!
    return p


length = float(input("Enter length of pendulum (m): "))
period = calc_period(length)
print(f"The period of your pendulum is {period:.2f} s.")

# Now perform exactly the same computation, 
# with the same input.
period = calc_period(length)
print(f"The period of your pendulum is {period:.2f} s.")

This prints

The period of your pendulum is 6.35 s.
The period of your pendulum is 6.35 s.

This is because without the global statement, the assignment g_0 = 400 created a new, local g_0 which exists only within the body of the function.

So inappropriate use of global statements make it possible to modify variables we do not wish to modify!

When is it appropriate to use global?

Sometimes, it may make sense to use a global variable to maintain state. Yes, there are those who would say this is never a good idea, but it does come up, and Python does have a global statement, so let’s look at an example anyway.

As one example, let’s say we wanted to keep track of how many times a function is called during the execution of a program (maybe counting attempts at making a network connection, or number of times a magic spell is used in a fantasy game). We could use a global variable for this.

times_foo_has_been_called = 0

def foo(x, y, z):
    global times_foo_has_been_called
    # do some foo work here, whatever that might be
    times_foo_has_been_called += 1
    return  # ... return some useful value, perhaps

That’s one example.

The important thing to remember is that Python will look outside the current code block for a free variable without the use of global, and that global should be used when we want to modify a global variable. These are two entirely different cases!2

You may also wish to read up on mutability and immutability (ITPACS, chapters 3 and 10), and pass by assignment (ITPACS, chapter 5) which is the only way Python passes arguments to functions.

Original author: Clayton Cafiero < [given name] DOT [surname] AT uvm DOT edu >

No generative AI was used in producing this material. This was written the old-fashioned way.

This material is for free use under either the GNU Free Documentation License or the Creative Commons Attribution-ShareAlike 3.0 United States License (take your pick).

Footnotes

  1. https://docs.python.org/3/reference/executionmodel.html↩︎

  2. Of course, if the variable in the outer scope is of a mutable type, that’s a different discussion.↩︎