Skip to content

functools Module Overview

The functools module provides higher-order functions and operations on callable objects. It's essential for functional programming patterns in Python.

import functools
# or
from functools import partial, wraps, lru_cache, cache, reduce

Module Contents at a Glance

Function Purpose Python Version
partial Freeze function arguments 2.5+
reduce Cumulative fold operation 2.6+
wraps Preserve decorator metadata 2.5+
lru_cache Bounded memoization (LRU) 3.2+
cache Unbounded memoization 3.9+
total_ordering Complete comparison ops 2.7+
singledispatch Type-based overloading 3.4+
cached_property Lazy cached attribute 3.8+
cmp_to_key Legacy comparison adapter 2.7+

How functools Fits into Python

Relationship to Other Modules

functools          — higher-order functions, caching, dispatch
├── partial        — similar to lambda but preserves metadata
├── reduce         — moved here from built-ins in Python 3
├── wraps          — essential companion to decorators (Ch 5.6)
├── lru_cache      — memoization with eviction policy
├── cache          — simpler memoization (Python 3.9+)
└── singledispatch — type-based dispatch

operator           — function versions of operators (Ch 5.4)
itertools          — iterator combinators (Ch 7.2)

Core Theme: Functions That Transform Functions

Every tool in functools takes a callable and produces a new callable:

from functools import partial, lru_cache, wraps

# partial: fix arguments → new function
square = partial(pow, exp=2)

# lru_cache: add memoization → cached function
@lru_cache(maxsize=128)
def fib(n): ...

# wraps: copy metadata → wrapper with correct identity
def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

Quick Examples

partial — Freeze Arguments

from functools import partial

def power(base, exponent):
    return base ** exponent

square = partial(power, exponent=2)
cube = partial(power, exponent=3)

print(square(5))  # 25
print(cube(5))    # 125

reduce — Fold a Sequence

from functools import reduce
import operator

numbers = [1, 2, 3, 4, 5]
product = reduce(operator.mul, numbers)
print(product)  # 120

lru_cache — Memoize Results

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(100))  # Instant
print(fibonacci.cache_info())
# CacheInfo(hits=98, misses=101, maxsize=128, currsize=101)

wraps — Preserve Metadata in Decorators

from functools import wraps

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        import time
        start = time.perf_counter()
        result = func(*args, **kwargs)
        print(f"{func.__name__}: {time.perf_counter() - start:.4f}s")
        return result
    return wrapper

@timer
def process(data):
    """Process data."""
    return sum(data)

print(process.__name__)  # 'process' (not 'wrapper')

total_ordering — Fill in Comparisons

from functools import total_ordering

@total_ordering
class Version:
    def __init__(self, major, minor):
        self.major = major
        self.minor = minor

    def __eq__(self, other):
        return (self.major, self.minor) == (other.major, other.minor)

    def __lt__(self, other):
        return (self.major, self.minor) < (other.major, other.minor)

# All six comparisons now work
v1, v2 = Version(1, 0), Version(2, 0)
print(v1 < v2)   # True (defined)
print(v1 <= v2)  # True (auto-generated)
print(v1 > v2)   # False (auto-generated)

singledispatch — Type-Based Overloading

from functools import singledispatch

@singledispatch
def process(data):
    raise NotImplementedError(f"Cannot process {type(data)}")

@process.register(list)
def _(data):
    return [x * 2 for x in data]

@process.register(str)
def _(data):
    return data.upper()

print(process([1, 2, 3]))  # [2, 4, 6]
print(process("hello"))    # HELLO

Choosing the Right Tool

Need Tool Example
Fix some arguments partial square = partial(pow, exp=2)
Cache function results lru_cache / cache Recursive DP, expensive queries
Write a decorator wraps Logging, timing, retry decorators
Fold sequence to value reduce Product, flatten, compose
Auto-generate comparisons total_ordering Custom sortable classes
Dispatch by type singledispatch Format different data types
Cache a property cached_property Expensive computed attributes

Section Map

Each function has a dedicated page with detailed coverage:

  • functools.cache — unbounded memoization for recursive algorithms
  • functools.lru_cache — bounded memoization with LRU eviction
  • functools.partial — partial function application
  • functools.reduce — cumulative fold operations
  • functools.wraps — metadata preservation for decorators
  • functools.total_ordering — auto-generate comparison methods
  • functools.singledispatch — single-argument type dispatch

Summary

Concept Key Point
Module purpose Higher-order functions and callable transformations
Most used wraps, lru_cache, partial
Caching cache (unbounded) vs lru_cache (bounded)
Decorators Always use @wraps(func)
Folding reduce works but prefer built-ins when available
Dispatch singledispatch avoids if/elif type chains

Key Takeaways:

  • functools is the Swiss army knife for functional programming in Python
  • wraps and lru_cache are used daily in production code
  • partial creates cleaner specialized functions than lambdas
  • reduce is powerful but often less readable than built-in alternatives
  • total_ordering and singledispatch reduce boilerplate in OOP code