PYTHON Contents

Decorators Basics (Function Wrapping)

Use decorators to standardize cross-cutting concerns like timing, retries, and input validation without repeating code.

On this page

Decorators Add Policy

Decorators wrap functions to add behavior consistently. In production, they are useful for policy enforcement (timeouts, retries, logging) if kept transparent.

Simple Timing Decorator

import time
from functools import wraps

def timed(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        try:
            return fn(*args, **kwargs)
        finally:
            elapsed_ms = (time.perf_counter() - start) * 1000
            print(f"event=timed fn={fn.__name__} elapsed_ms={elapsed_ms:.2f}")
    return wrapper

Usage

@timed
def work():
    return "ok"

Operational Checklist

  • Always use @wraps to preserve name and docstring.
  • Keep decorator behavior deterministic; avoid hidden network calls.
  • Make side effects (logging, retries) obvious to callers.

Failure Modes

  • Metadata loss: without @wraps, debugging and tracing suffer.
  • Hidden behavior: decorators stack and become hard to reason about.