PythonMastery
reference 3 min read · lesson 22 of 60 in Errors

UnboundLocalError: local variable referenced before assignment

1 · The lesson

read

What this error means

Python decides at compile time, not run time, which names inside a function are local. If a function assigns to a name anywhere in its body, that name is local for the whole function, including the lines that run before the assignment. If you read it before assigning, you get UnboundLocalError.

When you see it

text
Traceback (most recent call last):
  File "counter.py", line 8, in <module>
    bump()
  File "counter.py", line 5, in bump
    print(count)
UnboundLocalError: cannot access local variable 'count' where it is not associated with a value

The classic minimal reproduction:

python
count = 0

def bump():
    print(count)   # fails: count is local and has no value yet
    count = count + 1

bump()

Why it happens

The count = count + 1 on the last line makes count a local variable for the entire bump body. The earlier print(count) therefore looks at the local count, which has no value yet. It does not look at the module-level count = 0. The rule is consistent: the scope of a name is decided for the whole function, not line by line.

How to fix it

Option 1: declare the name with global or nonlocal. Use this rarely, because shared mutable state often leads to bugs.

python
count = 0

def bump():
    global count
    count = count + 1

For a name in an enclosing function (not module-level):

python
def make_counter():
    count = 0
    def bump():
        nonlocal count
        count += 1
        return count
    return bump

Option 2: pass the value in and return the new value. This is cleaner, easier to test, and has no shared state.

python
def bump(count):
    return count + 1

count = bump(count)

Option 3: use a mutable container. This works because you change the object, and you don't assign a new value to the name.

python
state = {"count": 0}

def bump():
    state["count"] += 1     # no assignment to `state` itself

When you'd see this in real code

  • A function reads a config flag, then later reassigns it for the rest of the function ("if no value passed, use default").
  • A closure tries to update a counter in the enclosing scope but forgets nonlocal.
  • Loop accumulators inside a function where someone "improved" the code by initialising the accumulator at the top of the module instead of inside the function.
  • NameError: name 'x' is not defined: Python could not find x in any scope. Different from UnboundLocalError, where it found a local but the local has no value yet.
  • SyntaxError: name 'x' is used prior to nonlocal declaration: you used the name before declaring nonlocal x.

See Also

Found this useful? Share it with a friend who’s learning Python.