How do decorators work in Python and how do I write them?

· Category: Python Programming

Short answer

A decorator is a function that takes another function as input and returns a new function (or callable) that adds behavior before or after the original. Use @decorator_name syntax to apply them.

Steps

  1. Write a wrapper function that accepts the original function.
  2. Define an inner function that calls the original and adds extra logic.
  3. Return the inner function.
  4. Apply with @my_decorator above the function definition.
from functools import wraps
import time

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        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

@timer
def slow_function():
    time.sleep(0.1)
    return "done"

slow_function()

Tips

  • Always use @wraps(func) from functools to preserve the original function's metadata.
  • Decorators can accept arguments by adding an outer factory function.
  • Classes can implement __call__ to act as decorators.
# Parameterized decorator
def repeat(n):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet():
    print("Hello")

greet()

Common issues

  • Forgetting @wraps causes the decorated function to lose its name and docstring.
  • Decorators that do not return the wrapper result break the function's return value.
  • Decorating methods requires careful handling of self; consider using descriptor-based decorators for classes.