Why doesn't this closure modify the variable in the enclosing scope?
closures, generator, python
Solution
There are two "better" / more Pythonic ways to do this on Python 2.x than using a container just to get around the lack of a nonlocal keyword.
One you mentioned in a comment in your code -- bind to a local variable. There is another way to do that:
Using a default argument
def make_incrementer(start):
def closure(start = start):
while True:
yield start
start += 1
return closure
x = make_incrementer(100)
iter = x()
print iter.next()
This has all the benefits of a local variable without an additional line of code. It also happens on the `x = make_incrememter(100)` line rather than the `iter = x()` line, which may or may not matter depending on the situation.
You can also use the "don't actually assign to the referenced variable" method, in a more elegant way than using a container:
Using a function attribute
def make_incrementer(start):
def closure():
# You can still do x = closure.start if you want to rebind to local scope
while True:
yield closure.start
closure.start += 1
closure.start = start
return closure
x = make_incrementer(100)
iter = x()
print iter.next()
This works in all recent versions of Python and utilizes the fact that in this situation, you already have an object you know the name of you can references attributes on -- there is no need to create a new container for just this purpose.
Problem
This bit of Python does not work: ``` def make_incrementer(start): def closure(): # I know I could write 'x = start' and use x - that's not my point though (: while True: yield start start += 1 return closure x = make_incrementer(100) iter = x() print iter.next() # Exception: UnboundLocalError: local variable 'start' referenced before assignment ``` I know how to fix that error, but bear with me: This code works fine: ``` def test(start): def closure(): return start return closure x = test(999) print x() # prints 999 ``` Why can I read the `start` variable inside a closure but not write to it? What language rule is causing this handling of the `start` variable? Update: I found this SO post relevant (the answer more than the question): Read/Write Python Closures