Module 02 - Functional Programming
Reading time: ~10 minutes | Level: Intermediate
Here is a question most Python developers answer wrong:
funcs = [lambda x: x * i for i in range(3)]
print(funcs[0](10)) # ?
print(funcs[1](10)) # ?
print(funcs[2](10)) # ?
Most developers predict 0, 10, 20.
Every single call prints 20.
Not a bug. Not a quirk. A precise consequence of how Python captures variables in closures - and how lambda evaluation is split between compile time and call time. Understanding this exactly is the kind of depth this module builds.
What This Module Covers
Functional programming in Python is not a separate paradigm - it is a set of tools baked into the language that the best Python engineers use every day without thinking about it. sorted() with a key function, map() over a data stream, a decorator that adds retry logic to any function, a generator that reads a 10 GB log file line by line without loading it into memory - all of these are functional programming in practice.
This module builds the engineering foundation for all of it. You will understand not just the syntax but the mechanics: why generators save memory, how decorators compose, what closures actually capture, and when a pure function matters in a system that has to scale.
The concepts here also serve as direct prerequisites for the Python concurrency module. async/await in Python is built on generators. Decorators power FastAPI's routing system. functools.lru_cache is how you make expensive computations viable at production scale. None of that is opaque once you understand the underlying model.
By the end of this module, you will read a decorator stack, a generator pipeline, or a functools.reduce call and understand exactly what is happening - not just that it works, but why, and what it costs.
Module Topics
| # | Lesson | What It Covers |
|---|---|---|
| 01 | Lambda Expressions | Anonymous function objects, the compile-time/call-time split, the loop-closure trap, the default-argument fix, and when lambda is and is not appropriate |
| 02 | map, filter, reduce | Lazy iterators, the pipeline model, functools.reduce and left-fold semantics, performance characteristics, and when to prefer list comprehensions |
| 03 | Generators and yield | Frame suspension, the generator state machine, send() and the coroutine protocol, yield from, memory-efficient data pipelines, and the foundation of async/await |
| 04 | Iterator Protocol | __iter__ and __next__, building custom iterators from scratch, infinite sequences, StopIteration, and how for loops actually work internally |
| 05 | Decorators | Function wrapping, functools.wraps, stacking decorators, parametrised decorators, class-based decorators, and real-world patterns from FastAPI, Flask, and production systems |
| 06 | Closures Deep Dive | Free variables and __closure__, cell objects, the nonlocal keyword, closure factories, and why closures are the foundation of every decorator |
| 07 | Pure Functions | Referential transparency, side effects, testability, memoisation, and why pure functions are the unit of reasoning in large systems |
| 08 | Immutability Strategies | Immutable data structures in Python (tuple, frozenset, types.MappingProxyType), frozen=True dataclasses, copy semantics, and defensive programming patterns |
| 09 | functools Module | lru_cache, cache, partial, reduce, wraps, total_ordering, singledispatch - the standard library's functional toolkit at engineering depth |
| 10 | Partial Application and Currying | functools.partial, manual currying, point-free style, pipeline composition, and how these patterns appear in real APIs and configuration systems |
Module Projects
| Project | Core Skills |
|---|---|
| Lazy Data Pipeline | Generators, iterators, map/filter, memory-efficient stream processing |
| Decorator Library | Parametrised decorators, functools.wraps, retry, rate-limit, cache decorators |
| Functional Config System | Pure functions, immutability, partial, functools.reduce, composable transformations |
| Mini Expression Evaluator | Closures, currying, higher-order functions, function composition |
Prerequisites
- Python Foundation course complete (or equivalent depth)
- Comfortable with functions, loops, and basic data structures
- Understand that functions are first-class objects in Python (they can be passed as arguments, returned from functions, and stored in variables)
How to Use This Module
Lessons build on each other. Read them in order.
map/filter/reduce (02) assumes you understand lambda from lesson 01.
Generators (03) introduces the suspension model that async/await is built on.
Decorators (05) requires closures - read lesson 06 alongside or first if closures feel uncertain.
functools (09) and partial/currying (10) synthesise everything that came before.
After every lesson: open your editor and implement the concepts cold, from memory. Reading examples builds familiarity. Writing them from scratch builds understanding.
The opening puzzle of every lesson is not decorative. Attempt a genuine prediction before reading. If you are wrong, that is the signal - you have found the precise gap the lesson closes.
The Engineering Standard
This module is written for engineers building production systems.
Generators appear in Django ORM querysets, SQLAlchemy result sets, and every async framework. Decorators are how FastAPI builds its entire routing and dependency injection system. functools.lru_cache is how you make a recursive Fibonacci viable at n=1000. Closures are how every well-designed callback API works without globals.
Understanding these tools at the mechanical level - not just the syntax - is what separates engineers who use Python from engineers who understand it. By the end of this module, you will not just know what a decorator does. You will know exactly what happens in memory when one is applied, what functools.wraps preserves and why it matters, and how to write a parametrised decorator that works correctly when stacked three deep.
That depth is not academic. It is the difference between debugging a decorator stack in five minutes and spending an afternoon on it.
