Beginners in Python frequently encounter unexpected behavior or UnboundLocalError when attempting to modify variables within functions that are defined outside. The issue stems from Python’s distinct rules for local and global variable scope; the solution involves explicit declaration using the global keyword or, preferably, structured data passing and return mechanisms.
The Problem
Many new Python developers struggle with understanding how variables are accessed and modified across different scopes, particularly when moving from global declarations to function bodies. This often leads to errors like UnboundLocalError, which occurs when a local variable is referenced before it has been assigned, even if a variable with the same name exists in the global scope. This confusion can hinder progress, making debugging challenging for those unfamiliar with Python’s specific scope resolution rules.
The Solution
To modify a global variable from within a function, the global keyword must be explicitly used. For read-only access, explicit declaration is not required. However, for maintainability and clarity, it is often more robust to pass variables as function arguments and return modified values.
# Demonstrating scope and resolution
global_variable = 100
def modify_global_incorrectly():
# This will cause an UnboundLocalError if 'global_variable' is modified without 'global'
# For example: global_variable += 1
# Python would interpret 'global_variable' as a new local variable here if assigned to.
print(f"Inside (read-only): {global_variable}") # This works for reading
def modify_global_correctly():
global global_variable
global_variable += 50
print(f"Inside (modified using global): {global_variable}")
def modify_via_return(value):
# Preferable approach: Pass value, modify, and return new value
value += 25
print(f"Inside (modified via return): {value}")
return value
print(f"Initial global_variable: {global_variable}")
modify_global_incorrectly() # Reads the global variable
# Attempting to modify without 'global' would raise an UnboundLocalError if uncommented:
# def attempt_to_modify_without_global():
# # This line would cause UnboundLocalError if uncommented and called:
# # global_variable += 1
# # print(f"Attempting to modify: {global_variable}")
# pass
modify_global_correctly() # Modifies the global variable using 'global' keyword
print(f"After modify_global_correctly: {global_variable}")
# Using the more robust pass-and-return pattern
new_value = modify_via_return(global_variable)
print(f"After modify_via_return (new_value is assigned, global_variable unaffected directly): {new_value}")
print(f"Global variable after modify_via_return: {global_variable}") # global_variable remains unchanged here without explicit assignment
# To update the global variable with the returned value:
global_variable = modify_via_return(global_variable)
print(f"Global variable updated by assignment: {global_variable}")
Why It Works
- Scope Resolution (LEGB Rule): Python resolves variable names using the LEGB rule: Local, Enclosing function locals, Global, Built-in. When a variable is read inside a function, Python searches these scopes in order.
- Local Assignment Creates Local Variable: If a variable is assigned a value within a function, Python treats it as a new local variable by default, even if a global variable with the same name exists. This prevents accidental modification of global state, but it leads to
UnboundLocalErrorif the local variable is then referenced before its assignment. - The
globalKeyword: Explicitly declaring a variable withglobal variable_nameinside a function tells Python that assignments tovariable_nameshould modify the variable in the global scope, rather than creating a new local one. - Parameter Passing and Return Values (Best Practice): The most robust and idiomatic Python approach is to pass variables as arguments to functions. The function then processes these arguments and explicitly
returns any new or modified values. This makes data flow explicit, improves function reusability, and reduces side effects, enhancing code readability and maintainability.