🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

Python functools Complete Guide 2026: lru_cache, partiell und Reduce

⏱️4 min read  ·  878 words

Das Functools-Modul von Python ist eines der am wenigsten genutzten und dennoch leistungsfähigsten Standardbibliotheksmodule. Im Jahr 2026 stellt functools Tools für Funktionen höherer Ordnung, Memoisierung, Teilanwendung und Funktionskomposition bereit, die Boilerplates überflüssig machen und den Code ausdrucksvoller machen. Diese vollständige Anleitung deckt alle Functools-Funktionen mit praktischen Beispielen ab.

functools.lru_cache und Cache

from functools import lru_cache, cache
import time

# Simple memoization — cache indefinitely
@cache  # Python 3.9+, same as lru_cache(maxsize=None)
def fibonacci(n: int) -> int:
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# LRU cache — keep only most recent N results
@lru_cache(maxsize=128)
def expensive_api_call(user_id: int) -> dict:
    time.sleep(0.5)  # simulate slow API
    return {"id": user_id, "name": "User"}

# Cache info and management
print(fibonacci.cache_info())  # CacheInfo(hits=X, misses=Y, maxsize=None, currsize=N)
fibonacci.cache_clear()

# Method-level cache (instance-level, not shared across instances)
class DataService:
    @lru_cache(maxsize=256)
    def get_user(self, user_id: int) -> dict:
        return fetch_from_db(user_id)

functools.partial – Teilanwendung

from functools import partial
import operator

# Create a new function with some args pre-filled
def power(base: float, exponent: float) -> float:
    return base ** exponent

square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(square(5))  # 25.0
print(cube(3))    # 27.0

# Useful with map/filter
double = partial(operator.mul, 2)
numbers = [1, 2, 3, 4, 5]
doubled = list(map(double, numbers))  # [2, 4, 6, 8, 10]

# Partial with keyword args
import requests
get_from_api = partial(requests.get, headers={"Authorization": "Bearer token123"})
response = get_from_api("https://api.example.com/users")

# In configuration/dependency injection
from functools import partial

def create_user(db, email: str, role: str = "user") -> dict:
    return db.insert("users", {"email": email, "role": role})

create_admin = partial(create_user, db=prod_db, role="admin")
admin = create_admin("admin@example.com")

functools.reduce

from functools import reduce
import operator

# Sum a list (use sum() instead in practice)
total = reduce(operator.add, [1, 2, 3, 4, 5])  # 15

# Product of list (no built-in)
product = reduce(operator.mul, [1, 2, 3, 4, 5])  # 120

# Flatten nested list
nested = [[1, 2], [3, 4], [5, 6]]
flat = reduce(operator.add, nested)  # [1, 2, 3, 4, 5, 6]

# Compose functions (right to left)
def compose(*functions):
    return reduce(lambda f, g: lambda x: f(g(x)), functions)

pipeline = compose(str.upper, str.strip, str.lower)
print(pipeline("  Hello World  "))  # "HELLO WORLD"

# Deep dictionary merge
dicts = [{"a": 1}, {"b": 2, "c": 3}, {"d": 4}]
merged = reduce(lambda acc, d: {**acc, **d}, dicts)  # {"a":1,"b":2,"c":3,"d":4}

functools.wraps

from functools import wraps
import time, logging

logger = logging.getLogger(__name__)

def log_calls(func):
    @wraps(func)  # preserves __name__, __doc__, __wrapped__, __annotations__
    def wrapper(*args, **kwargs):
        logger.info(f"Calling {func.__name__}")
        result = func(*args, **kwargs)
        logger.info(f"Done {func.__name__}")
        return result
    return wrapper

def measure(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"{func.__name__}: {elapsed*1000:.2f}ms")
        return result
    return wrapper

@log_calls
@measure
def process_data(data: list) -> list:
    return sorted(data)

# Without @wraps, process_data.__name__ would be "wrapper"
print(process_data.__name__)  # "process_data" (correct!)

functools.total_ordering

from functools import total_ordering

@total_ordering  # generates __le__, __lt__, __ge__, __gt__ from __eq__ and one comparison
class Version:
    def __init__(self, major: int, minor: int, patch: int = 0):
        self.major = major
        self.minor = minor
        self.patch = patch

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Version):
            return NotImplemented
        return (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch)

    def __lt__(self, other: "Version") -> bool:
        return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch)

    def __repr__(self) -> str:
        return f"Version({self.major}.{self.minor}.{self.patch})"

versions = [Version(2, 0), Version(1, 9, 5), Version(3, 0), Version(1, 9, 4)]
print(sorted(versions))  # [1.9.4, 1.9.5, 2.0, 3.0]
print(Version(1, 9) < Version(2, 0))  # True
print(Version(3, 0) >= Version(2, 1))  # True (generated!)

functools.singledispatch – Methodenüberladung

from functools import singledispatch

@singledispatch
def process(obj):
    raise TypeError(f"Cannot process {type(obj)}")

@process.register(int)
def _(obj: int) -> str:
    return f"Integer: {obj}"

@process.register(str)
def _(obj: str) -> str:
    return f"String: '{obj}'"

@process.register(list)
def _(obj: list) -> str:
    return f"List with {len(obj)} items"

@process.register(dict)
def _(obj: dict) -> str:
    return f"Dict with {len(obj)} keys: {list(obj.keys())}"

print(process(42))           # "Integer: 42"
print(process("hello"))      # "String: 'hello'"
print(process([1, 2, 3]))    # "List with 3 items"

# Useful for serialization/display of varied types without isinstance chains

functools.cached_property

from functools import cached_property
import statistics

class Dataset:
    def __init__(self, data: list[float]):
        self._data = data

    @cached_property
    def mean(self) -> float:
        print("Computing mean...")
        return statistics.mean(self._data)

    @cached_property
    def stdev(self) -> float:
        print("Computing stdev...")
        return statistics.stdev(self._data)

    @cached_property
    def sorted_data(self) -> list[float]:
        print("Sorting...")
        return sorted(self._data)

ds = Dataset([3, 1, 4, 1, 5, 9, 2, 6])
print(ds.mean)       # "Computing mean..." then value
print(ds.mean)       # value directly (cached)
print(ds.stdev)      # "Computing stdev..." then value

Python-Funktionstools im Jahr 2026 sind für sauberen, effizienten Code unerlässlich. Verwenden Sie @cache für die Memoisierung, „partial()“ für die Konfigurationsinjektion, @wraps für die Transparenz des Dekorators, @total_ordering für Vergleichsklassen, @singledispatch für den typbasierten Versand und „cached_property“ für verzögert berechnete Attribute. Diese Tools ersetzen Standardtexte und verdeutlichen die Absicht.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা