Python functools
In this page:
Caching with lru_cache
The @lru_cache decorator memoizes a function's return value against its exact arguments, so repeated calls with the same inputs skip recomputation entirely and return the cached result instantly. This turns naive exponential-time recursive functions, like a plain recursive Fibonacci, into fast linear-time ones with a single decorator.
Example: Caching with lru_cache
from functools import lru_cache
@lru_cache
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
print(fib(30))
Partial Functions with partial
partial() takes a function plus some of its arguments and returns a new callable with those arguments already locked in, needing only the remaining ones when called. It's a clean way to specialize a general-purpose function into a narrower one without writing a wrapper def by hand.
Example: Partial Functions with partial
from functools import partial
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2)
print(square(5))
Custom Sorting with cmp_to_key
cmp_to_key() bridges old-style two-argument comparison functions (which return negative, zero, or positive) into the single-argument key functions that sorted() and list.sort() expect in modern Python. It exists mainly for adapting legacy comparison logic that predates Python 3's key-function-only sorting API.
Example: Custom Sorting with cmp_to_key
from functools import cmp_to_key
def compare(a, b):
return a - b
nums = [3, 1, 2]
print(sorted(nums, key=cmp_to_key(compare)))
Wrapping Decorators with wraps
@wraps is applied inside a custom decorator's inner wrapper function, and it copies the original function's __name__, __doc__, and other metadata onto the wrapper. Without it, decorated functions would misleadingly report the wrapper's own name and docstring instead of the real function's, breaking introspection tools and confusing debugging.
Example: Wrapping Decorators with wraps
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@log
def greet():
"""Greets the user."""
print("hi")
print(greet.__name__, greet.__doc__)
Accumulating Values with reduce
reduce() repeatedly applies a two-argument function to a running accumulator and each next item in a sequence, collapsing the whole sequence down to one final value. It's the general-purpose tool behind patterns like summing a list or finding a maximum, though for those specific cases Python's built-in sum() and max() are usually clearer.
Example: Accumulating Values with reduce
from functools import reduce
numbers = [1, 2, 3, 4]
total = reduce(lambda a, b: a + b, numbers)
print(total)
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first: