How to Resolve "UnboundLocalError: local variable referenced before assignment" in Python
The UnboundLocalError: local variable 'variable_name' referenced before assignment error in Python occurs when you try to use a variable within a function before it has been assigned a value within that function's scope, even if a variable with the same name exists in an outer (e.g., global) scope.
This guide explains why this error happens, and presents several solutions, including the global and nonlocal keywords, and best-practice alternatives that often make your code cleaner and easier to understand.
Understanding the UnboundLocalError
The core issue is Python's scoping rules. When you assign to a variable anywhere within a function, Python treats that variable as local to the function, unless you explicitly declare it as global or nonlocal. This local variable shadows any variable with the same name in an outer scope. The UnboundLocalError occurs if you try to read from a local variable before you've assigned to it.
name = 'Alice' # Global variable
def example():
# ⛔️ UnboundLocalError: local variable 'name' referenced before assignment
print(name) # Trying to READ 'name' *before* assignment
name = 'Tom' # This assignment makes 'name' a LOCAL variable within example()
example()
Why it happens: The print(name) line tries to access the local name variable. The presence of the assignment name = 'Tom' later in the function makes Python treat name as local throughout the entire function. Because the local name has not been assigned a value before the print statement, the error occurs. The global name defined outside the function is ignored (shadowed) within the function's scope.
Solution 1: Declare the Variable Before Using It (Within the Function)
The simplest fix, if you intend to work with a local variable, is to ensure you assign a value to it before you try to use it:
def example():
name = 'Tom' # Assign to 'name' FIRST
print(name) # Now it's safe to read 'name'
example() # Output: Tom
- This creates a local
namethat is completely separate from the globalname. This is often the correct fix if you don't intend to modify a global variable.
Solution 2: Using the global Keyword (Use Sparingly)
If you do intend to modify a global variable from within a function, use the global keyword:
name = 'Alice' # Global variable
def example():
global name # Declare 'name' as global within the function
print(name) # Now refers to the global 'name'
name = 'Tom' # Modifies the global 'name'
example() # Output: Alice
print(name) # Output: Tom (global variable has been changed)
global name: This line tells Python: "When I usenamein this function, I'm referring to the global variablename, not a local one."- Now,
print(name)correctly accesses the globalname, andname = 'Tom'modifies the global variable.
Overuse of global variables can make code harder to understand and maintain. It's generally better to pass variables as arguments and return values (see Solution 3). Use global only when truly necessary.
Solution 3: Passing Variables as Arguments (Recommended)
The best and cleanest way to avoid UnboundLocalError (and avoid global variables) is to pass any needed variables as arguments to the function, and to return any modified values:
name = 'Alice'
def example(first_name): # 'first_name' is a local parameter
full_name = first_name + ' Smith'
return full_name
result = example(name) # Pass the global 'name' as an argument
print(result) # Output: Alice Smith
print(name) # Output: Alice (global 'name' is unchanged)
- The
examplefunction now takesfirst_nameas an argument. Inside the function,first_nameis a local variable, completely independent of the globalname. - The function returns the modified value, which you can then assign to a variable in the calling scope (if needed).
- This is the preferred approach because it makes your functions more:
- Self-contained: They don't rely on (or modify) external state.
- Reusable: You can call them with different inputs.
- Testable: Easier to test in isolation.
- Easier to understand: The data flow is explicit.
Solution 4: Returning Values from Functions
If you need a modified value outside of the function, return it:
name = 'Alice'
def example():
new_name = 'Tom' # The result of the function
return new_name # Return the new value
name = example() # The global variable is set to the returned value
print(name) # Output: Tom
- This approach avoids the
globalkeyword and promotes immutability, resulting in cleaner, more predictable code.
Solution 5: Using the nonlocal Keyword (Nested Functions)
The nonlocal keyword is used in nested functions (functions defined inside other functions) to modify variables in the nearest enclosing scope that is not global.
def outer():
message = '' # 'message' is local to 'outer', but nonlocal to 'inner'
def inner():
nonlocal message # Declare 'message' as nonlocal
message = 'hello world'
print(message)
inner()
print(message) # Output: hello world
outer()
nonlocal message: This line is crucial. It tells Python thatmessageinsideinner()refers to themessagevariable in the enclosingouter()function, not a new local variable withininner().- Without
nonlocal, the assignmentmessage = 'hello world'would create a new local variable namedmessageinsideinner(), shadowing the outermessage.
Best Practices to Avoid UnboundLocalError
- Pass arguments, return values: This is the most important practice. Favor passing variables to functions as arguments and returning results, rather than modifying global variables directly.
- Initialize variables: Always assign a value to a variable before you try to read it within a function's scope.
- Use
globalsparingly: Only useglobalwhen you absolutely must modify a global variable from within a function. Overuse ofgloballeads to code that is hard to reason about. - Use
nonlocalcorrectly: Usenonlocalonly in nested functions when you need to modify a variable in an enclosing (but non-global) scope. - Avoid shadowing Do not declare variables with the same names in inner and outer scope to avoid unexpected behaviour.
Conclusion
The UnboundLocalError in Python arises from the interaction of local and global (or nonlocal) scopes.
By understanding Python's scoping rules, and preferring to pass arguments and return values rather than using global or nonlocal (unless strictly necessary), you can prevent this error and write cleaner and more maintainable Python code.
Always remember to initialize your local variables before attempting to use them.