Python functools Module

The functools module provides higher-order functions and operations on callable objects. It includes tools for creating decorators, caching function results, and adapting function signatures.

Use Cases:
- Caching expensive function results with lru_cache or cache
- Creating partial function applications with partial
- Preserving function metadata in decorators with wraps
- Reducing sequences to single values with reduce
- Implementing rich comparison methods with total_ordering

Example 1: Caching expensive computations
    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(50))  # Instant, thanks to caching
    print(fibonacci.cache_info())
    # CacheInfo(hits=48, misses=51, maxsize=128, currsize=51)

Example 2: Creating partial functions
    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(3))    # 27

The wraps decorator is essential when writing decorators, as it copies the wrapped function's name, docstring, and other attributes to the wrapper. The reduce function applies a two-argument function cumulatively to sequence elements, though list comprehensions or generator expressions are often preferred for clarity.
