Python · The language, not just syntax

How do decorators work and what are their pitfalls?

MediumdecoratorsclosuresfunctoolsUpdated Oct 2026
Quiz this track

Short answer

A decorator is a callable that takes a function and returns a replacement, usually a wrapper that adds behaviour around the original call. functools.wraps preserves the wrapped function's metadata.

The @decorator syntax is sugar. Writing @log above def f is equivalent to f = log(f). Because the wrapper is a closure over the original function, it can run code before and after the call, retry it, cache results or register it.

python
import functools
import time

def timed(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        try:
            return func(*args, **kwargs)
        finally:
            elapsed = time.perf_counter() - start
            print(func.__name__, round(elapsed, 4))
    return wrapper

@timed
def work(n):
    return sum(range(n))

work(1000)
The wrapper accepts any arguments and forwards them. wraps keeps __name__ and __doc__ useful for debugging and docs.

Variants and pitfalls

  • Decorators with arguments need an extra outer function: @retry(times=3)
  • Stacked decorators apply bottom-up: the closest decorator wraps first
  • functools.lru_cache and cache are ready-made memoisation decorators
  • Without wraps, introspection tools and debuggers see the wrapper signature

Decorators run at import time. A decorator that performs I/O, reads configuration or registers global state can make imports slow and order-dependent. They also obscure control flow, so use them for cross-cutting concerns such as logging, timing, authentication and caching rather than core business logic.

Decorating a method with a plain function wrapper works because the wrapper is a function descriptor. Class-based decorators are useful when the decorator itself needs state.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1How would you write a decorator that takes arguments?
  2. 2In what order do stacked decorators execute?
  3. 3Why is functools.wraps important?
  4. 4What are the downsides of hiding logic in decorators?

Say it in the interview

A decorator is a callable that receives a function and returns a replacement. The @ syntax is just reassignment, and the replacement is usually a closure that adds behaviour before or after the call. I always use functools.wraps so names, docstrings and signatures survive. I keep decorators for cross-cutting concerns like timing, retries, caching and auth, because they run at import time and can hide control flow.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Python mock interview and get scored feedback on depth, clarity and confidence.