The other day I had to explain why in Python in contrast to Perl/Lisp/Scheme one can’t rebind variable outside of the local scope besides the global scope, i.e. the following function will result in an UnboundLocalError exception in Python 2.x
def outer(): count = 0 def inner(): count += 1 # rebinding inner() print count
>>> outer() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "scope.py", line 8, in outer inner() File "scope.py", line 6, in inner count += 1 # rebinding UnboundLocalError: local variable 'count' referenced before assignment
There are several workarounds.
For one thing it is possible to use a variable holding a mutable object:
def outer(): ns = dict(count=0) def inner(): ns['count'] += 1 # rebinding inner() print ns['count']
>>> outer() 1
Another approach is to use a function object itself to store the variable:
def outer(): outer.count = 0 def inner(): outer.count += 1 # rebinding inner() print outer.count
>>> outer() 1
The good news is that there is no need for workarounds anymore in Python 3 which introduced nonlocal keyword:
def outer(): count = 0 def inner(): nonlocal count count += 1 # rebinding inner() print(count)
>>> outer() 1
Nice post! Your second workaround is a bit dodgy, though – rather than modifying non-local state you’re really modifying global state. If you were returning the inner function, rather than calling it, the closed-over state would be shared between different calls to outer.
I often use a 1-element list as the state box for a mutating closure.
*sigh* I love closures.
Hi xtian,
Probably my example didn’t emphasize it, but ‘outer’ function could be nested into another function (thus no global state modification) and all I was caring about was a variable in the outside scope and how to modify it.
Maybe the following example explains my intentions better than the old one:
>>> outer()
Quite often I would use classes and avoid workarounds altogether by storing state in a class instance.