| name | capture-state-closure |
| description | For persistent state: closures capture outer variables, alternative to classes for simple state, factory functions that remember context. |
capture-state-closure
When to Use
- Need state that persists across function calls
- Simpler than defining a class
- Creating specialized functions from a template
- Memoization with accessible cache
- Callback factories
When NOT to Use
- Multiple methods needed (use class)
- State is complex (use class)
- Need inheritance or protocols
The Pattern
Nested function captures variables from enclosing scope.
def make_counter(start=0):
"""Create a counter function with persistent state."""
count = start
def counter():
nonlocal count
count += 1
return count
return counter
c = make_counter(10)
c()
c()
Example (from pytudes)
def memo(f):
"""Memoize function f."""
table = {}
def fmemo(*args):
if args not in table:
table[args] = f(*args)
return table[args]
fmemo.memo = table
return fmemo
@memo
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
fibonacci.memo
def Sym(s, symbol_table={}):
"""Find or create unique Symbol for string s."""
if s not in symbol_table:
symbol_table[s] = Symbol(s)
return symbol_table[s]
assert Sym('quote') is Sym('quote')
def make_multiplier(factor):
"""Create a function that multiplies by factor."""
def multiply(x):
return x * factor
return multiply
double = make_multiplier(2)
triple = make_multiplier(3)
double(5)
triple(5)
Key Principles
- Inner function sees outer scope: Variables are captured
- Mutable objects shared: Lists, dicts can be modified
- nonlocal for rebinding: Needed to reassign immutable captured vars
- Default args persist: Mutable default arg is like static variable
- Expose internals: Attach captured state as attribute for inspection