Why can't Python increment variable in closure?
closures, python
Solution
You can't re-bind closure variables in Python 2. In Python 3, which you appear to be using due to your `print()`, you can declare them `nonlocal`:
def foo():
counter = 1
def bar():
nonlocal counter
counter += 1
print("bar", counter)
return bar
bar = foo()
bar()
Otherwise, the assignment within `bar()` makes the variable local, and since you haven't assigned a value to the variable in the local scope, trying to access it is an error.
In Python 2, my favorite workaround looks like this:
def foo():
class nonlocal:
counter = 1
def bar():
nonlocal.counter += 1
print("bar", nonlocal.counter)
return bar
bar = foo()
bar()
This works because mutating a mutable object doesn't require changing what the variable name points to. In this case, `nonlocal` is the closure variable and it is never reassigned; only its contents are changed. Other workarounds use lists or dictionaries.
Or you could use a class for the whole thing, as @naomik suggests in a comment. Define `__call__()` to make the instance callable.
class Foo(object):
def __init__(self, counter=1):
self.counter = counter
def __call__(self):
self.counter += 1
print("bar", self.counter)
bar = Foo()
bar()
For completeness, I'll suggest that you could also write the function as a generator using the last `gen2func` decorator in this answer of mine. This lets you use regular local variables to maintain state across calls, because the function isn't really a function and never actually exits. However, this is more a "ain't that cool" than a recommended solution!
Problem
In this code snippet I can print the value of counter from inside the bar function ``` def foo(): counter = 1 def bar(): print("bar", counter) return bar bar = foo() bar() ``` But when I try to increment counter from inside the bar function I get an UnboundLocalError error. ``` UnboundLocalError: local variable 'counter' referenced before assignment ``` Code snippet with increment statement in. ``` def foo(): counter = 1 def bar(): counter += 1 print("bar", counter) return bar bar = foo() bar() ``` Do you only have read access to variables in the outer function in a Python closure?