An enclosing function lexically surrounds a nested function and supplies bindings that the nested function can still access. This relationship creates a closure: calling the outer function produces a new inner function carrying access to the outer invocation’s variables. section 6.12
Python finds names through LEGB: local, enclosing function, global, then built-ins. A nested function searches its enclosing function’s scope after its own local scope, so separate outer invocations can preserve separate values. section 6.5 section 6.12
A closure with a private counter
def foo(): call_counter = 0 def bar(y): nonlocal call_counter call_counter += 1 return f'y = {y}, call_counter = {call_counter}' return bar b = foo() for i in range(10, 100, 10): print(b(i)) Each call to b updates the call_counter belonging to foo’s invocation, producing counts from 1 through 9. The nonlocal declaration allows the nested function to update that enclosing binding.
Parameterizing a returned function
def foo(x): def bar(y): return x * y return bar f = foo(10) print(f(20)) Here, bar accesses x from its enclosing invocation. The same pattern supports a password generator whose returned function remembers the allowed characters. section 6.12
Visualizes two password-generating functions created by separate invocations, making their retained enclosing bindings easier to compare. section 6.12

