What is a decorator in Python?

A decorator is a function that wraps another function to add behaviour before or after it runs applied with the @ syntax.

Python

Overview

A decorator is a callable that takes a function, wraps it with extra behaviour, and returns the new wrapper. The `@decorator` syntax is shorthand for `func = decorator(func)`. Decorators are used for logging, authentication, caching, timing, and more.

Key Points

  • •`@decorator` above a function is syntactic sugar for `func = decorator(func)`.
  • •The wrapper function should accept `*args, **kwargs` and call the original function.
  • •Use `functools.wraps(func)` to preserve the original function's name and docstring.
  • •Decorators can be stacked they are applied bottom-up.
  • •Class decorators and decorators with arguments follow the same pattern but add extra layers.

Examples

Simple timing decorator

python
import time
import functools

def timer(func):
    @functools.wraps(func)  # preserves func.__name__ and __doc__
    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)

slow_function()  # prints: slow_function took 0.1001s

Decorator with arguments

python
def repeat(times):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for _ in range(times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")  # prints 3 times

Stacking decorators (applied bottom-up)

python
@require_auth       # applied second
@timer              # applied first
def dashboard():
    ...
# equivalent to: dashboard = require_auth(timer(dashboard))

Pro Tip

Always use `@functools.wraps(func)` inside your wrapper. Without it, `func.__name__` and `func.__doc__` are replaced by the wrapper's which breaks introspection, logging, and some testing tools.