Non-local statement of Learning Python Part II

Keywords: Python

In the following example, taster returns the nested function for later invocation. The search for variable state conforms to the usual variable search rules.

>>> def tester(start):
...     state = start
...     def nested(label):
...         print(label, state)
...     return nested
... 
>>> F = tester(0)
>>> F('spam')
spam 0
>>> F('ham')
ham 0

By default, nested functions cannot change variables within closure functions:

>>> def tester(start):
...     state = start
...     def nested(label):
...         print(label, state)
...         state += 1
...     return nested
... 
>>> F = tester(0)
>>> F('spam')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in nested
UnboundLocalError: local variable 'state' referenced before assignment

Changing variables using nonlocal

>>> def tester(start):
...     state = start
...     def nested(label):
...         nonlocal state
...         print(label, state)
...         state += 1
...     return nested
... 
>>> F = tester(0)
>>> F('spam')
spam 0
>>> F('ham')    #state can be accumulated
ham 1
>>> F('eggs')
eggs 2

Just like the usual reference to closure functions, how many times we call tester, there are copies of fewer states in memory. The state object in the closure scope is bound to the nested function object returned by the function. Each call produces a completely different state object, such as updating the state of one function without affecting the other. The following example illustrates:

>>> G = tester(42)
>>> G('spam')
spam 42
>>> G('eggs')
eggs 43
>>> F('bacon')
bacon 3

Boundary conditions

Although nonlocal is very useful, there are some things that must be known beforehand. First, unlike global, variables declared by nonlocal must be assigned beforehand, otherwise errors will be thrown:

>>> def tester(start):
...     def nested(label):
...         nonlocal state
...         state = 0
...         print(label, state)
...     return nested
... 
  File "<stdin>", line 3
SyntaxError: no binding for nonlocal 'state' found
>>> def tester(start):
...     def nested(label):
...         global state
...         state = 0
...         print(label, state)
...     return nested
... 
>>> F = tester(0)
>>> F('abc')
abc 0
>>> state
0

Secondly, nonlocal restricted scopes are only found in closure functions. Nonlocal does not go up in the global scope of the module or Python built-in scope outside the function:

>>> spam = 99
>>> def tester():
...     def nested():
...         nonlocal spam
...         print('Current=', spam)
...         spam += 1
...     return nested
... 
  File "<stdin>", line 3
SyntaxError: no binding for nonlocal 'spam' found

Posted by Unforgiven on Thu, 07 Feb 2019 21:24:18 -0800