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
local
unless 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 += 1
is mainly a shortcut fora = a + 1
, so in your examplea
is 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
nonlocal
statement:Python 2 doesn't have
nonlocal
so the canonical hack is to wrap the variable in a mutable container (typically alist
but 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
nonlocal
variable 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).