Python’s global
keyword allows us to change the value of module-level variables inside functions.
Sounds so simple and useful, doesn’t it? Well, yeah. I’m going to show you how it can be useful in
the simple sense and situations where it can drive people nuts.
Simple Usage¶
Consider the following top.py
script. We have a single module-level (aka global
) variable here,
and we change its value in the function done
.
1 2 3 4 5 6 7 8 9 10 11
are_we_done = False
def mark_done():
global are_we_done
are_we_done = True
print("Done?", are_we_done)
mark_done()
print("Done?", are_we_done)
Running this, we get the following output:
Done? False
Done? True
The reason we were able to change the value of the global variable are_we_done
from inside the
mark_done
function is because we declared it as such on line 5. If that declaration isn’t there,
we’d just be defining a new function level variable called are_we_done
inside the mark_done
function. Which is not what we wanted.
Refer Directly¶
Note that declaring variables as global
is needed only when we’re modifying the value of the
variable. That means if we are only accessing the variable, we don’t need to declare it as
global
. This is how capitalized constant variables work in most Python scripts:
CURRENT_PLANET = "Earth"
def get_moon_count():
if CURRENT_PLANET == "Earth":
return 1
else:
raise ValueError("No idea!")
print(get_moon_count())
This, of course, prints out 1
. Here, we are using the CURRENT_PLANET
global variable inside the
function without declaring it as global. Accessing doesn’t require explicitly declaring as
global
.
Modifying the Referred Object¶
A small note on the terms we’ve been using here. Accessing doesn’t require global
declaration, but
modifying does. Now look at the following code snippet:
CALLS = []
def record_call(phone_number):
CALLS.append(phone_number)
record_call("123-45-678")
record_call("987-65-432")
print(CALLS)
Here, since we are appending to the CALLS
list, is that considered modifying the global variable?
The answer is no. We are merely accessing the CALLS
variable’s value, which happens to be a
list
, on which we call the .append
method. There’s no modifying going on here so far. The
.append
method, however, will change the state of the list
object. But for the purposes of
using the CALLS
variable here, we are only accessing it. So, we don’t need to declare it as
global
.
So what does modifying mean? Simply put, if you want to reassign a global variable, it’s considered as modifying.
Assigning without Declaring¶
This behaviour of global variables causes some slightly unintuitive situations. For example, consider the following piece of code:
1 2 3 4 5 6 7 8
is_server_up = False
def mark_server_up():
print(is_server_up)
mark_server_up()
In this script, we are using the global variable is_server_up
on line 5, without declaring it as
global
, and it works fine. Now, we add another line to this function:
1 2 3 4 5 6 7 8 9
is_server_up = False
def mark_server_up():
print(is_server_up)
is_server_up = True
mark_server_up()
If we run this script, we get the following error:
Traceback (most recent call last):
File "/check.py", line 9, in <module>
mark_server_up()
File "/check.py", line 5, in mark_server_up
print(is_server_up)
UnboundLocalError: local variable 'is_server_up' referenced before assignment
Okay, we kind of expected an error because we are trying to modify a global variable without declaring it. But note that the error comes from line 5, not on line 6, where we are modifying the variable. The error message gives a hint on what’s happening.
local variable 'is_server_up' referenced before assignment
Since we didn’t declare is_server_up
as global, and since we are setting a value to
is_server_up
, Python decided that we want a local variable in our function with the same name.
With that understanding, it looks like we are referencing the is_server_up
local variable before
assigning a value to it. That’s the error we see here.
Conclusion¶
Global variables have their place, but, if it’s not for constant-like values, I’d recommend against using global variables at all. It might make sense for small one-off scripts, and when it does, keep the above small details in mind.