UnboundLocalError: cannot access local variable 'X' where it is not associated with a value

avatar
Borislav Hadzhiev

Last updated: Apr 10, 2024
6 min

banner

# UnboundLocalError: cannot access local variable 'X' where it is not associated with a value

The Python "UnboundLocalError: cannot access local variable 'X' where it is not associated with a value" occurs for multiple reasons:

  • Referencing a local variable before assigning a value to it in a function.
  • Only assigning a value to a variable if a certain condition is met.
  • Only assigning a value to a variable in a try/except statement.

To solve the error, mark the variable as global before referencing it in the function or make sure to assign a value to the variable regardless if a condition is met.

unboundlocalerror cannot access local variable where it is not associated

Here is an example of how the error occurs.

main.py
country = 'Austria' def my_func(): # โ›”๏ธ UnboundLocalError: cannot access local variable 'X' where it is not associated with a value print(country) country = 'Germany' my_func()

accessing local variable before it is declared

We reference the country variable in the function before assigning a value to it.

Assigning a value to the country variable within the function makes it a local (to the function) variable and we try to access the variable before assigning a value to it.

The local country variable shadows the country variable that is declared in the global scope.

# Mark the variable as global before accessing it within the function

To solve the error, mark the variable as global before accessing it within your function.

main.py
country = 'Austria' def my_func(): # ๐Ÿ‘‡๏ธ Mark as global first global country print(country) country = 'Germany' # ๐Ÿ‘‡๏ธ Call function to reassign the variable my_func() # ๐Ÿ‘‰๏ธ Austria # ๐Ÿ‘‡๏ธ Now the `country` variable is set to `Germany` my_func() # ๐Ÿ‘‰๏ธ Germany

mark variable as global

If a variable is assigned a value within a function's body, it is a local variable unless explicitly declared as global.

When we mark the variable as global, we tell to the interpreter to look for it in the global scope.

The first call to the function reassigns the global country variable, setting it to "Germany".

Once we call the function the second time and print the country variable, it's already set to "Germany".

# Local variables shadow global ones with the same name

You can reference the country global variable from within the function, however, if you assign a value to the variable, the local variable shadows the global one.

main.py
country = 'Austria' def my_func(): # ๐Ÿ‘‡๏ธ Can access global variable here print(country) my_func() # ๐Ÿ‘‰๏ธ Austria

can access global variables within function

If you assign a value to the variable within the function without marking it as global, the assignment only applies to the function's local scope.

main.py
country = 'Austria' def my_func(): # ๐Ÿ‘‡๏ธ This only applies within the function country = 'Germany' print(country) print(country) # ๐Ÿ‘‰๏ธ Austria my_func() # ๐Ÿ‘‰๏ธ Germany print(country) # ๐Ÿ‘‰๏ธ Austria

declaring variable with same name within function

The country variable in the function is set to 'Germany' and the country variable outside the function has a value of 'Austria'.

This behavior is very confusing and should generally be avoided.

It is much better to pick different names and avoid clashes.

# Assigning values to local variables from an outer function

If you have a nested function and are trying to assign a value to the local variables from the outer function, use the nonlocal keyword.

main.py
def outer(): # ๐Ÿ‘‡๏ธ Initialize country variable country = '' def inner(): # ๐Ÿ‘‡๏ธ Mark country as nonlocal nonlocal country country = 'Germany' print(country) # ๐Ÿ‘‡๏ธ Invoke inner function inner() print(country) # ๐Ÿ‘‰๏ธ "Germany" outer()

using nonlocal keyword

The nonlocal keyword allows us to work with the local variables of enclosing functions.

Note that we had to initialize the country variable in the outer function, but we were able to change its value in the inner function.

Had we not used the nonlocal statement, the call to the print() function would have returned an empty string.

main.py
def outer(): # ๐Ÿ‘‡๏ธ Initialize country variable country = '' def inner(): # ๐Ÿ‘‡๏ธ Declares country in inner function's scope country = 'Germany' print(country) inner() # ๐Ÿ‘‡๏ธ Refers to outer's country variable print(repr(country)) # ๐Ÿ‘‰๏ธ "" outer()

declaring local variable without nonlocal

If you get the error "Local variable referenced before assignment", check out the following article.

# Returning a value that is used to reassign the global variable

An alternative solution to using the global keyword is to return a value from the function and use the value to reassign the global variable.

main.py
country = 'Austria' def my_func(): print(country) # ๐Ÿ‘‰๏ธ Austria new_country = 'Germany' return new_country result = my_func() print(result) # ๐Ÿ‘‰๏ธ Germany country = result print(country) # ๐Ÿ‘‰๏ธ Germany

use function return value

We simply return the value that we eventually assign to the country global variable.

# Passing the global variable as an argument to the function

You should also consider passing the global variable as an argument to the function.

main.py
country = 'Austria' def my_func(ctry): location = 'Linz, ' + ctry return location result = my_func(country) print(result) # ๐Ÿ‘‰๏ธ Linz, Austria

take the value as an argument

We passed the country global variable as an argument to the function.

When we assign a value to a variable in a scope, that variable becomes local to that scope and shadows variables with the same name in the outer scope.

If we assign a value to a variable in a function, the variable is assumed to be local unless explicitly declared as global.

# Only assigning a value to a variable is a condition is met

Another common cause of the error is assigning a value to a variable only if a condition is met and trying to access it after.

main.py
def my_func(): if 5 > 10: country = 'Germany' print(country) # โ›”๏ธ UnboundLocalError: cannot access local variable 'country' where it is not associated with a value return f'Country: {country}' my_func()

only assigning value if condition is met

The if statement checks if 5 is greater than 10.

The condition is never met, so the country variable never gets set.

When we try to access the variable after the if block, we get the error because the variable was never associated with a value.

To solve the error, set the variable to a default value before the if block.

main.py
def my_func(): country = None if 5 > 10: country = 'Germany' print(country) return f'Country: {country}' print(my_func())

initialize variable before if block

We initialized the country variable to None outside the if block.

We used a default value of None, but you can also use an empty string "" or 0 as the default value, depending on your use case.

The variable is set even if the if condition isn't met, so the error is never raised.

# Only assigning a value to a variable in a try/except statement

Another cause of the error is only assigning a value to a variable in a try/except statement.

main.py
def my_func(): try: raise ValueError('Something went wrong') country = 'Germany' print(country) except ValueError: pass # โ›”๏ธ UnboundLocalError: cannot access local variable 'country' where it is not associated with a value return f'Country: {country}' print(my_func())

only setting value in try block

Notice that an error is raised before the country variable is declared in the try block.

The variable is never given a value, so when we try to access it in the return statement, an UnboundLocalError occurs.

To solve the error, set the variable to an initial value before the try statement.

main.py
def my_func(): country = None try: raise ValueError('Something went wrong') country = 'Germany' print(country) except ValueError: pass return f'Country: {country}' print(my_func()) # ๐Ÿ‘‰๏ธ Country: None

initialize variable before try block

We initialized the country variable to None before the try block.

We used None as the default value, but you can also set the variable to an empty string "" or 0 depending on your use case.

Even if an error is raised in the try block, the variable is still associated with a value because we've initialized it prior.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev