Python decorators look like magic. They're not. They're just functions that take functions and return functions. Once you see the mechanics, you can build tools that clean up cross-cutting concerns — logging, retries, caching, auth — without cluttering business logic.
First-Class Functions and Closures
Everything starts here. Functions are objects. You can assign them, pass them, nest them. A closure captures variables from its enclosing scope.
inner remembers msg after outer returns. That's the engine under every decorator.
The Basic Decorator Pattern
A decorator wraps a function, adding behavior before, after, or around the call.
The @timer syntax is sugar for slow_add = timer(slow_add). The original function gets replaced by wrapper.
Preserve Metadata with functools.wraps
@wraps(func) copies __name__, __doc__, __module__, __annotations__, and more. Always use it.
Decorators That Accept Arguments
Need a configurable retry? Three levels: the outer factory takes config, returns a decorator, which returns the wrapper.
Class Decorators
A class with __call__ works as a decorator. Useful when you need state.
Real-World Patterns
| Pattern | Use Case | Key Insight |
|---|---|---|
| Cache (lru_cache) | Expensive pure functions | Built-in, thread-safe, maxsize controls memory |
| Retry | Flaky I/O | Exponential backoff + jitter prevents thundering herd |
| Logging | Observability | Structured logs with context, not print statements |
| Auth | Route protection | Stack decorators: @login_required @admin_required |
| Metrics | Latency/error rates | Increment counters in wrapper, export to Prometheus |
"Decorators let you separate what a function does from how it's executed. That separation is the heart of clean architecture.
— Python Software Foundation
Stacking Order Matters
Decorators apply bottom to top. @a @b def f() means a(b(f)). The innermost wrapper runs first.
✦
Start small. Wrap a function with a timer. Add @wraps. Build a retry with configurable backoff. Then compose them. The pattern scales from scripts to services. Your future self will thank you when a flaky dependency goes down and your code just works.










