← Back to Python Course | Chapter 11: Advanced Python | Lesson 11 of 12

Python functools

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

python
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

python
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

python
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

python
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

python
from functools import reduce

numbers = [1, 2, 3, 4]
total = reduce(lambda a, b: a + b, numbers)
print(total)

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.