pythonintermediate
Python Functools and Decorator Patterns
Useful decorator patterns with functools including caching, retry, timing, and rate limiting.
pythonPress ⌘/Ctrl + Shift + C to copy
import functools
import time
from typing import Callable, TypeVar, ParamSpec
P = ParamSpec("P")
R = TypeVar("R")
# Retry decorator with exponential backoff
def retry(max_attempts: int = 3, delay: float = 1.0):
def decorator(func: Callable[P, R]) -> Callable[P, R]:
@functools.wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
for attempt in range(1, max_attempts + 1):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts:
raise
wait = delay * (2 ** (attempt - 1))
print(f"Attempt {attempt} failed: {e}. Retrying in {wait}s")
time.sleep(wait)
raise RuntimeError("Unreachable")
return wrapper
return decorator
# Timing decorator
def timed(func: Callable[P, R]) -> Callable[P, R]:
@functools.wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__} took {elapsed:.4f}s")
return result
return wrapper
# Memoize with TTL
def ttl_cache(seconds: int = 300):
def decorator(func: Callable[P, R]) -> Callable[P, R]:
cache: dict[str, tuple[float, R]] = {}
@functools.wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
key = str((args, sorted(kwargs.items())))
now = time.time()
if key in cache and now - cache[key][0] < seconds:
return cache[key][1]
result = func(*args, **kwargs)
cache[key] = (now, result)
return result
return wrapper
return decorator
# Usage
@retry(max_attempts=3, delay=0.5)
@timed
def fetch_data(url: str) -> str:
import urllib.request
with urllib.request.urlopen(url) as resp:
return resp.read().decode()
@ttl_cache(seconds=60)
def get_config() -> dict:
return {"key": "value"} # expensive operationUse Cases
- Adding retry logic to flaky operations
- Performance profiling with timing decorators
- Caching expensive computations with expiry
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
pythonintermediate
Python Context Manager Patterns
Create custom context managers with __enter__/__exit__ and contextlib for resource management.
Best for: Automatic resource cleanup and lifecycle management
#python#context-manager
pythonintermediate
Python Dataclass Advanced Patterns
Advanced dataclass usage with validation, post-init processing, slots, and frozen instances.
Best for: Type-safe data models without ORMs
#python#dataclass
pythonbeginner
Memoize Functions with lru_cache
Cache expensive function results automatically using functools.lru_cache.
Best for: Recursive algorithms
#python#caching
pythonintermediate
Python Enum Advanced Patterns
Use Python enums with custom values, methods, auto(), and Flag for type-safe constants.
Best for: type-safe constants
#python#enum