P29 · Functions, Decorators & Generators

closures, decorators, iterators & generators

Python's functional core, rebuilt by hand: closures that carry state, decorators as ordinary wrap-and-return code, and generators whose suspended frames power lazy pipelines, context managers - and, one pillar on, async/await.

Three features that look like separate pieces of Python syntax — closures, decorators, generators — are one idea seen from three angles: a function is a value, and a function that has been suspended or wrapped is still just a value you can pass around. Getting that straight is unusually high-leverage, because almost everything that feels magical later in this discipline turns out to be built from these three, and this pillar is where they stop being magical.

Closures come first: a function that captures state from its enclosing scope, rebinds it with nonlocal, and can therefore act as a factory, a partial application, or a composition of other functions. Decorators are then revealed as ordinary code — wrap and return, with functools.wraps to keep the identity of what you wrapped — extended to the three-layer factory that takes arguments, stacked deliberately so the order is a decision rather than an accident, and written as classes with __call__ when they need state. Generators come last and reach furthest: you rebuild the iterator protocol, replace it with yield, exploit laziness on streams too large or endless to materialise, and then find that the same suspended frame is what a context manager is made of via contextlib, and what send() turns into a coroutine — which is exactly the door P33 walks through to reach async/await.

Functions as valuesclosures capture stateDecoratorswrap and return, then factoriesGeneratorsyield suspends a frameThe doorwaycontext managers, then coroutines
Foundation first: one idea in three costumes, and the frame that suspends is what async is built on.
P29 · Functions, Decorators & Generators — TransformerLab