Using Global Variables in Python

This post will focus on global variables. Let's consider the peculiarities of working with these variables and what errors may arise in our code in connection with their use.

Table of Contents

Global Variables in Python


Creating a global variable is easy in Python. We just need to create a variable at the module level. It is better to do this at the very beginning of the file (module).

#!/usr/bin/env python3
"""Python script with a global variable."""

counter = 0

# checking the current module namespace
print(globals())
Output:
{'__name__': '__main__', ..., 'counter': 0}
Technically, in Python, we give names to objects by associating a name with a value. Hence, the namespace.
So, if counter=0 , the name "counter" is associated with the integer 0 (an object of class "int").
When we say "create a variable in Python", it means that we define a certain name and associate it with some Python object.

We can also create a global variable in a function. After calling the function, we can access and use the new global variable.

def create_global_variable():
    global new_variable  # this line is required here
    new_variable = "value"

# creates a new global variable when the function is called
create_global_variable()

print(globals())
print("New variable:", new_variable)
Output:
{'__name__': '__main__', ...,
'create_global_variable': <function create_global_variable at ...>,
'new_variable': 'value'}

New variable: value

You may notice the use of the keyword global along with the variable name. This keyword can be used in Python functions. This is necessary to change the value of a global variable or to create a new global variable within a function.


As mentioned earlier, variables that we want to use as globals are best created at the very beginning. We need to create them before using them in functions.

# variable at the module level
counter = 0

def get_values():
    print("Counter:", counter)
    print("New variable:", new_variable)

print("The namespace at the time of the function call:")
print(globals())

get_values()

# it is also a variable at the module level
new_variable = "value"
Output:
The namespace at the time of the function call:
{'__name__': '__main__', ...,
'counter': 0,
'get_values': <function get_values at ...>}

Counter: 0

Traceback (most recent call last):
...
    print("New variable:", new_variable)
NameError: name 'new_variable' is not defined

The module namespace has the variable name "counter" and the function name "get_values". The name "new_variable" does not exist at the time we call the function that uses it.

We need the variable to be there, at least, before calling the function to get rid of the error.

counter = 0

def get_values():
    print("Counter:", counter)
    print("New variable:", new_variable)

new_variable = "value"

print("The namespace at the time of the function call:")
print(globals())

get_values()
Output:
The namespace at the time of the function call:
{'__name__': '__main__', ...,
'counter': 0,
'get_values': <function get_values at ...>,
'new_variable': 'value'}

Counter: 0
New variable: value

We can easily get confused about our variables. We need to be careful about where and what names we use and how we change the values of variables.


Using Global Variables and the "global" Keyword in a Function


In the next example, we will perform some actions with variables:

Increment the counter value by 1 in the function update_counter_value;
Reset the counter value to 0 in the function reset_counter_value;
Get the counter value to print it in the function read_counter_value;
Get the variable values to perform comparison and arithmetic operations in the function check_counter_value.

To change the value of a variable, we use the global keyword in a function (update, reset).

If we don't change the value of the variable in the function, we don't need the global keyword (read, check).

In the reset_counter_value function, I intentionally omit the global counter to demonstrate that in this case we are getting a local variable in the function.

max_counter_value = 3
counter = 0

def update_counter_value():
    global counter
    counter += 1
    print("The counter has been updated")

def reset_counter_value():
    # global counter
    counter = 0
    print("Local variable counter:", locals()["counter"])
    print("Global variable counter:", globals()["counter"])

def check_counter_value():
    if counter == 0:
        msg = "The counter value is zero"
    else:
        diff = max_counter_value - counter
        msg = f"Max counter value - counter = {diff}"
    print(msg)
    
def read_counter_value():
    print("Current counter value:", counter)

read_counter_value()
update_counter_value()
read_counter_value()
reset_counter_value() # the value is not reset
read_counter_value()
check_counter_value()
Output:
Current counter value: 0
The counter has been updated
Current counter value: 1
Local variable counter: 0
Global variable counter: 1
Current counter value: 1
Max counter value - counter = 2

If a variable is assigned a value anywhere in the function body, it is considered local unless explicitly declared as global. Even if a variable has the same name as a global variable, changes to that local variable will not affect the value of the global variable.

To reset the counter, we need to update the reset_counter_value function.

def reset_counter_value():
    global counter # this line is required here
    counter = 0
    print("The counter has been reset")
Output:
Current counter value: 0
The counter has been updated
Current counter value: 1
The counter has been reset
Current counter value: 0
The counter value is zero

What if a Global Variable Is Not Updated (Errors)?


1. We haven't created the variable yet, but we're using it somewhere.

# missing create_counter function call

def create_counter():
    global counter
    counter = 0

def read_counter_value():
    print("Current counter value:", counter)

# create_counter() - should be here
read_counter_value()
Output:
Traceback (most recent call last):
...
    print("Current counter value:", counter)
NameError: name 'counter' is not defined

2. We forgot to explicitly state that we are assigning a new value to a global variable in a function.

counter = 1

def reset_counter_value():
    # global counter - should be here
    counter = 0
    
reset_counter_value()
print("Counter:", counter)
Output:
Counter: 1

3. We forgot to explicitly state that we are modifying a global variable in a function.

counter = 0

def update_counter_value():
    # global counter - should be here
    counter += 1

update_counter_value()
The output depends on the version of Python.
UnboundLocalError: local variable 'counter' referenced before assignment
UnboundLocalError: cannot access local variable 'counter' where it is not associated with a value

4. We forgot to assign a value to a global variable. The name "counter" here does not refer to any object (value).

# missing counter = 0

print(globals())

def update_counter_value():
    global counter
    counter += 1

update_counter_value()
Output:
{'__name__': '__main__', ..., '__file__': 'test.py'}

Traceback (most recent call last):
...
    counter += 1
NameError: name 'counter' is not defined

If we do not encounter any error, but the value of the variable is not updated, we need to check the process of using the variable in the program flow.

Are we using the correct variable name?
Do we update a global variable before we use it somewhere?
Have events occurred that should change the value of the variable?

Conclusion


A global variable is often used in Python programs when we need to pass the value of a specific variable to different functions. A global variable allows us to have a value shared by functions that is always up-to-date.

If we have a small standalone script that performs a specific task, then global variables are not a big evil.

You should not use such variables if the program is complex or consists of several modules (files). It will be difficult to deal with the state of these variables.

Popular posts from this blog

Tkinter Button Widget