I have some code from a beginner's coding exercise:
numbers = []
i = 0
def populate(maximum, step):
while i < maximum:
numbers.append(i)
i = i + step
populate(10, 2)
Which fails with the stack trace:
Traceback (most recent call last):
File "test_python.py", line 9, in <module>
populate(10, 2)
File "test_python.py", line 5, in populate
while i < maximum:
UnboundLocalError: local variable 'i' referenced before assignment
Here is my understanding of the problem so far...
i
is an int and therefore it is immutable, andnumbers
is a list and is mutable- Since
i
is immutable, it can be read while it is out of scope. However, overwritting it while it is not in scope (ie. in thepopulate
function), causes anUnboundLocalError
- Since
numbers
is a mutable list, appending to it does not cause an overwrite and therefore does not cause anUnboundLocalError
If a simple change is made to the
populate
method, the program works successfully (due toi
not being overwritten)def populate(maximum, step): new_i = i while new_i < maximum: numbers.append(i) new_i = new_i + step
If I comment out the
i = i + 1
line, the while loop (obviously) runs forever, but the program does not fail.
My question is then, why does Python fail when it hits the while loop on line 5, instead of the actual problem on line 7 (i = i + 1
)? Is this some artifact of the interpreter taking the while loop as a block of code?
This piece of code fails in the correct spot:
def populate(maximum, step):
while i < maximum:
raise Exception("foo")
Stack trace:
Traceback (most recent call last):
File "test_python.py", line 12, in <module>
populate(10, 2)
File "test_python.py", line 6, in populate
raise Exception("foo")
Exception: foo
Another note: This only seems to be the case when the variable is used within the start of the control block (ie. while i < maximum
). And the same behavior occurs for every type of control block: while, for, if, elif, etc.