Functional Tools
Functional Programming in Python
Python is not a purely functional language — it supports multiple styles. But it has strong functional programming tools, and knowing them makes certain classes of problems significantly cleaner.
The functional mindset treats functions as the primary unit of composition. Rather than building large, stateful procedures, you build small, pure functions and combine them. Python's functools module is the home of the most important tools for doing this well.
partial — Pre-filling Arguments
functools.partial creates a new function from an existing one with some arguments already filled in.
partial(power, exponent=2) returns a new function — identical to power but with exponent permanently set to 2. You can call square with just the base. cube with just the base.
This is called partial application — specialising a general function into a more specific one. You write the general logic once, then derive specific versions from it.
send_welcome has the template and sender fixed. Only recipient changes per call. partial eliminates repetitive argument passing without creating a whole new function.
lru_cache — Memoisation
lru_cache (Least Recently Used cache) is a decorator that automatically caches a function's return values. When called with the same arguments again, it returns the cached result instantly — without rerunning the function.
The first call computes all intermediate Fibonacci values and caches them. The second call returns the result immediately from cache. The time difference is dramatic.
Without lru_cache, fibonacci(35) makes over 29 million recursive calls. With it, each unique n is computed exactly once.
maxsize=128 limits the cache to 128 entries — the least recently used entries are evicted when the cache is full. maxsize=None gives an unlimited cache (also available as @cache in Python 3.9+).
cache_info() reports hits, misses, current size, and maximum size — useful for understanding how effectively the cache is being used.
One constraint: lru_cache only works with hashable arguments. Lists and dictionaries cannot be cached over — use tuples instead (as shown with step_sizes).
reduce — Accumulating a Result
functools.reduce applies a function cumulatively to a sequence, reducing it to a single value.
reduce(f, [a, b, c, d]) computes f(f(f(a, b), c), d). Each step takes the accumulated result and the next item and produces a new accumulated result.
An optional initial value makes the starting point explicit:
Be honest about when reduce is the right tool. For simple sums and products, the built-in sum() and math.prod() are clearer. reduce earns its place when you need a custom accumulation that doesn't fit neatly into built-ins — finding a maximum by a custom key, building a nested structure, composing transformations.
total_ordering — Completing Comparison Methods
You met this briefly in the dunder methods lesson. total_ordering is a class decorator that fills in missing comparison methods given __eq__ and one of __lt__, __le__, __gt__, or __ge__:
You defined __eq__ and __lt__. total_ordering derived __le__, __gt__, and __ge__ automatically. All six comparison operators work. sorted() and max() work.
The tuple comparison (major, minor, patch) < (other.major, other.minor, other.patch) is elegant — Python compares tuples element by element, naturally implementing semantic versioning logic.
Composing Functions
A functional pattern worth knowing: building a pipeline where the output of one function feeds into the next.
compose(f, g, h) returns a function that applies h first, then g, then f — right to left, matching mathematical function composition. This is a pattern from functional programming that appears in data pipelines, middleware stacks, and transformation chains.
What You Have Learned
functools provides the tools for composing, specialising, and optimising functions in a clean, reusable way.
The key ideas:
partial(func, *args, **kwargs)— creates a new function with some arguments pre-filledlru_cache(maxsize=n)— memoises a function's results; transformative for recursive algorithmslru_cacherequires hashable arguments — use tuples, not listsreduce(func, iterable, initial)— folds a sequence into a single accumulated valuetotal_ordering— derive all six comparison operators from just__eq__and one other- Function composition — building pipelines by chaining small, pure functions
In the next lesson, you'll learn regular expressions — Python's tool for finding, extracting, and transforming text by pattern rather than by exact match.