Python Advanced
Python functools Module
The functools module offers powerful tools for working with functions themselves, including accumulating values, caching results, and pre-filling arguments.
reduce() — Accumulating a Result
reduce() applies a function cumulatively to the items of an iterable, combining them into one single result, similar to running a rolling total across a list.
from functools import reduce
numbers = [1, 2, 3, 4]
product = reduce(lambda a, b: a * b, numbers)
print(product)lru_cache — Caching Function Results
lru_cache is a decorator that remembers previous results of a function call, so calling it again with the same arguments returns the cached answer instantly instead of recomputing it. This is especially powerful for recursive functions.
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(fib(30))partial() — Pre-filling Arguments
partial() creates a new function with some arguments already fixed, useful when you repeatedly call the same function with one argument staying constant.
from functools import partial
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2)
print(square(5))
print(square(9))wraps — Preserving Function Metadata
When you write your own decorators, the wrapped function normally loses its original name and docstring. functools.wraps fixes this by copying that metadata onto the wrapper function.
from functools import wraps
def log_call(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_call
def greet(name):
"""Say hello."""
return f"Hello {name}"
print(greet.__name__)cached_property
cached_property turns a method into a property that computes its value once and stores it, so future accesses reuse the cached value instead of recalculating it every time.
from functools import cached_property
class Report:
def __init__(self, data):
self.data = data
@cached_property
def total(self):
print("Calculating...")
return sum(self.data)
r = Report([1, 2, 3])
print(r.total)
print(r.total) # uses cached value, no recalculationUse lru_cache for pure functions (same input always gives the same output) — caching functions with side effects can lead to stale or incorrect results.
