What is “UnboundLocalError: local variable ‘…’ referenced before assignment”?
UnboundLocalError
is a specific type of NameError
in Python. It occurs when you try to access a local variable within a function or method before a value has been assigned to it within that same function or method.
This error can be confusing because you might have a global variable with the same name. However, if you assign a value to a variable anywhere inside a function, Python treats that variable as local to that function for its entire scope.
Common Causes and Solutions
Let’s explore the scenarios that lead to this error.
1. Modifying a Global Variable Inside a Function
The most common cause is trying to modify a global variable without explicitly telling Python that you intend to do so.
Problematic Code
count = 0
def increment():
# Python sees this assignment and assumes 'count' is a local variable.
count = count + 1
print(count)
# This will raise an UnboundLocalError
increment()
When Python compiles the increment
function, it sees the assignment count = ...
. This tells Python that count
is a local variable. However, when the function executes, it tries to read the value of count
from the right side of the expression (count + 1
) before a value has been assigned to the local count
. The global count
is ignored, leading to the error.
Solution: Use the global
Keyword
To modify a global variable from within a function, you must use the global
keyword to declare your intent.
count = 0
def increment():
global count # Tell Python we are using the global 'count'
count = count + 1
print(count)
increment() # Output: 1
print(f"Global count is now: {count}") # Output: Global count is now: 1
2. Variable Assignment is Conditional
If a variable is only assigned a value inside a conditional block (if
, for
, try
), and that block is never entered, the variable will not exist when you try to access it later in the function.
Problematic Code
def get_status_message(status_code):
if status_code == 200:
message = "OK"
# If status_code is not 200, 'message' is never assigned.
return f"Status: {message}"
# This will raise an UnboundLocalError
print(get_status_message(404))
When get_status_message(404)
is called, the if
condition is false, so the line message = "OK"
is skipped. The return
statement then tries to access message
, which has not been assigned a value in the local scope.
Solution: Ensure the Variable is Always Assigned
Make sure the variable is assigned a value in all possible execution paths before it is accessed. A common practice is to initialize it with a default value at the beginning of the function.
def get_status_message(status_code):
message = "Unknown Status" # Initialize with a default value
if status_code == 200:
message = "OK"
elif status_code == 404:
message = "Not Found"
return f"Status: {message}"
print(get_status_message(404)) # Output: Status: Not Found
print(get_status_message(500)) # Output: Status: Unknown Status
3. Modifying a Variable in a Nested Function (Closures)
A similar issue arises with nested functions when you try to modify a variable from an enclosing (but not global) scope.
Problematic Code
def outer_function():
value = 10
def inner_function():
# Python assumes 'value' is local to inner_function due to the assignment.
value = value + 5
print(value)
inner_function()
# This will raise an UnboundLocalError
outer_function()
Solution: Use the nonlocal
Keyword
The nonlocal
keyword (introduced in Python 3) tells the interpreter that a variable is from the nearest enclosing scope that is not global.
def outer_function():
value = 10
def inner_function():
nonlocal value # Use the 'value' from outer_function
value = value + 5
print(f"Inner value: {value}")
inner_function()
print(f"Outer value: {value}")
outer_function()
# Output:
# Inner value: 15
# Outer value: 15
Conclusion
UnboundLocalError
is always a sign of a scope-related issue. To fix it, you need to be clear about which variable you are trying to access:
- If you mean to modify a global variable, use the
global
keyword. - If you mean to modify a variable in an enclosing function’s scope, use the
nonlocal
keyword. - Otherwise, ensure your local variable is assigned a value in all possible code paths before you try to read from it.
Leave a comment