def some_func(a):
def access_a():
print(a)
access_a()
outputs the value of a. However, if I want to change a in the nested function like this:
def some_func(a):
def change_a():
a += 1
print(a)
change_a()
it raises UnboundLocalError exception.
I know a is a nonlocal variable, but why can I access it without declaring nonlocal a?
Python scoping rules 101:
a name bound in a function body is considered
localunless explicitely declaredglobal(Python 2.x and 3.x) ornonlocal(Python 3.x only). This holds true whereever the assignment happens in the function's body. Trying to read a local variable before it's bound is of course an error.if a name is read but not bound in a function's body, it will be looked up in enclosing scopes (outer function(s) if any then global scope). NB: functions arguments are de facto local names so they will never be looked up in enclosing scopes.
Note that
a += 1is mainly a shortcut fora = a + 1, so in your exampleais local (bound in the function's body and not explicitely declared global or nonlocal), but you try to read it (the rhs ofa = a+1) before it's bound.In Python 3 you can solve this with a
nonlocalstatement:Python 2 doesn't have
nonlocalso the canonical hack is to wrap the variable in a mutable container (typically alistbut any mutable object would do):which is quite ugly to say the least.
Now while closures are quite handy, they are mostly the functional counterpart of objects : a way to share state between a set of functions while preserving encapsulation of this state, so if you find you have a need for a
nonlocalvariable perhaps a proper class might be a cleaner solution (though possibly not for your example that doesn't return the inner function but only uses it internally).