Creating Multiple Counters From A Single Function Using Nonlocal Statement In Python

The aim of this playbook🏁 is a commentary under SICP and SICP-in-PYTHON, illustrating a simple example of a local-state function returning another function allowing for the creation of multiple counters.

1. instructions

  • The returned function must be nested in function
  • The variable must be explicitly declared in the nested function
  • Only then can you modify in the parent scope and keep the state for repeated calls
def make_counter(n):
def incr():
nonlocal n
n = n + 1
print(n)
return incr
~~~
>>> c1 = make_counter(1)
>>> c2 = make_counter(99)
>>> c1()
2
>>> c1()
3
>>> c2()
100
>>> c1()
4
  • If you omit/comment out in the code above you get
def make_counter(n):
def incr():
n = n + 1
print(n)
return incr

>>> c1 = make_counter(1)
>>> c1()

Traceback (most recent call last):
File "c:/Users/Admin/Documents/workspace/work.log/kb/sicp/s09_03.py", line 10, in <module>
c() # 2
File "c:/Users/Admin/Documents/workspace/work.log/kb/sicp/s09_03.py", line 4, in incr
n = n+"yyy"
UnboundLocalError: local variable 'n' referenced before assignment
The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. 
This is important because the default behavior for binding is to search the local namespace first.
The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope.
Names listed in a nonlocal statement, unlike those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).
Names listed in a nonlocal statement must not collide with pre-existing bindings in the local scope.

2. links

Technical Support Engineer of Behavioural Data Platform (Snowplow Analytics). On comparison of programming languages, history of computing, and raw playbooks.