Skip to main content

How to Solve "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 name that is completely separate from the global name. 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 use name in this function, I'm referring to the global variable name, not a local one."
  • Now, print(name) correctly accesses the global name, and name = 'Tom' modifies the global variable.
warning

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.

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 example function now takes first_name as an argument. Inside the function, first_name is a local variable, completely independent of the global name.
  • 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 global keyword 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 that message inside inner() refers to the message variable in the enclosing outer() function, not a new local variable within inner().
  • Without nonlocal, the assignment message = 'hello world' would create a new local variable named message inside inner(), shadowing the outer message.

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 global sparingly: Only use global when you absolutely must modify a global variable from within a function. Overuse of global leads to code that is hard to reason about.
  • Use nonlocal correctly: Use nonlocal only 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.