reference
3 min read
·
lesson 22 of 60 in Errors
UnboundLocalError: local variable referenced before assignment
1 · The lesson
readWhat 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 getUnboundLocalError.
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 valueThe 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
Thecount = 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` itselfWhen 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.
Related errors
NameError: name 'x' is not defined: Python could not findxin any scope. Different fromUnboundLocalError, 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 declaringnonlocal x.
See Also
- All Python errors: the full index, by type and by when it happens.
- Functions: scope rules in depth.
- Closures: where
nonlocalmatters. - cheat-scope: LEGB lookup reminder.
Found this useful? Share it with a friend who’s learning Python.