Global Variables in Python
Learn how Python global variables work, how to modify them with the global keyword, avoid UnboundLocalError pitfalls, and when to use alternatives.
Global variables in Python are variables declared outside of any function. They live for the full lifetime of the program and can be read from anywhere — but modifying them inside a function requires the global keyword. This page covers how global variables work, the pitfalls to avoid, and when to reach for better alternatives.
What Are Global Variables?
A global variable is created at the module (top-level) scope — outside of any function or class. Any code in the same module can read it without any special declaration.
Python uses the LEGB rule to resolve names: it searches Local → Enclosing → Global → Built-in scopes in that order. A global variable sits at the "G" level, so every function can find it after exhausting its own local and enclosing scopes. See Python Scope for a full explanation of all four levels.
Reading vs. Modifying Global Variables
Reading a global variable (always works)
By default, a function can read any global variable without any special syntax:
language = "Python"
def print_language():
print(language) # reads the global
print_language() # Output: PythonThe global keyword — required for modification
If you try to assign to a variable inside a function, Python creates a new local variable instead of updating the global one. To modify the global, you must declare it with the global keyword:
counter = 0
def increment():
global counter # tell Python we mean the global 'counter'
counter += 1
print("Counter:", counter)
increment() # Output: Counter: 1
increment() # Output: Counter: 2
print(counter) # Output: 2Without global counter, the line counter += 1 would raise an UnboundLocalError because Python would try to read a local variable called counter before it was assigned.
The UnboundLocalError Pitfall
This is the most common mistake with global variables. The moment Python sees any assignment to a name inside a function, it treats that name as local throughout the entire function — even lines before the assignment:
x = 10
def broken():
print(x) # ERROR — Python sees the assignment below and marks x as local
x = 20
broken()
# UnboundLocalError: local variable 'x' referenced before assignmentFix it by adding global x at the top of the function if you genuinely need to modify the global, or by renaming the local variable if you want an independent copy.
Variable Shadowing
Assigning to a name inside a function without the global keyword creates a local variable that shadows the global — the global is not changed:
count = 100
def show_count():
count = 5 # local variable — shadows the global 'count'
print("Inside function:", count) # 5
show_count()
print("Outside function:", count) # 100 — global is unchangedShadowing is not an error, but it can be confusing. Use distinct names to make the intent obvious.
global Inside Nested Functions
If you need to reach a module-level global from an inner (nested) function, use global — not nonlocal. nonlocal only reaches the immediately enclosing function's scope, not the module level:
total = 0
def outer():
def inner():
global total # reaches module scope
total += 10
inner()
outer()
outer()
print("total:", total) # Output: total: 20Compare this with nonlocal, which modifies the enclosing function's variable but leaves the module-level global untouched:
x = "global"
def outer():
x = "outer"
def inner():
nonlocal x # modifies outer()'s x, not the module-level x
x = "inner"
inner()
print("outer x after inner():", x) # inner
outer()
print("global x after outer():", x) # global — unchangedFor a deeper look at nonlocal, see Python Scope.
Module-Level Constants — The Good Use Case
The most legitimate use of module-level globals is for constants — values that are set once and never changed at runtime. By convention, write them in UPPER_SNAKE_CASE:
MAX_RETRIES = 3
DEFAULT_TIMEOUT = 30
def connect(host, retries=MAX_RETRIES, timeout=DEFAULT_TIMEOUT):
print(f"Connecting to {host} with {retries} retries, timeout={timeout}s")
connect("db.example.com")
# Output: Connecting to db.example.com with 3 retries, timeout=30sConstants never need the global keyword because you only read them, never reassign.
Best Practices
1. Prefer function arguments and return values
Passing data through function signatures makes code easier to test and reason about. This pure function is simpler than using a mutable global counter:
def increment(counter):
return counter + 1
counter = 0
counter = increment(counter)
counter = increment(counter)
print("counter:", counter) # Output: counter: 22. Reserve globals for true module-wide constants
Use globals for values that are genuinely fixed for the entire run of the program (MAX_CONNECTIONS, APP_VERSION, configuration loaded once at startup). Avoid mutable globals that change over time.
3. Use descriptive, UPPER_SNAKE_CASE names for constants
A name like MAX_RETRIES is immediately recognizable as a module constant. A name like r is not.
4. Initialize before use
Declare all global variables at the top of the module, before any functions that use them. This prevents NameError if a function is called before the variable would otherwise be defined.
5. Be careful with threads
If multiple threads call functions that modify the same global variable, you get a race condition. Protect shared mutable state with a threading.Lock, or redesign to avoid shared state altogether. See Python Variables for a broader overview of variable types in Python.
Summary
| Situation | What to do |
|---|---|
| Read a global inside a function | Nothing special needed |
| Modify a global inside a function | Add global <name> at the top of the function |
| Modify an enclosing function's variable | Use nonlocal <name> |
| Share a fixed value across many functions | Declare a module-level constant in UPPER_SNAKE_CASE |
| Share mutable state between functions | Prefer function arguments and return values |