Decorators

Wrap a function to add behaviour without changing its code.

Syntax@decorator def my_function(): ...

A decorator is a function that takes another function and returns an enhanced version of it. You apply one with the @ syntax on the line above a function.

Common uses

  • Logging when a function runs.
  • Timing how long it takes.
  • Caching results, checking permissions, and more.

Example

Example · python
def shout(func):
    def wrapper(name):
        return func(name).upper()
    return wrapper

@shout
def greet(name):
    return f'hello, {name}'

print(greet('ada'))

# Output:
# HELLO, ADA

When to use it

  • A @login_required decorator checks authentication before every protected view function runs.
  • A @timer decorator wraps a function to log how many milliseconds it takes to execute.
  • A @retry decorator automatically retries a flaky network call up to three times on failure.

More examples

Basic decorator

Creates a decorator that wraps greet() to convert its return value to uppercase.

Example · python
def shout(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()
    return wrapper

@shout
def greet(name):
    return f'hello, {name}!'

print(greet('world'))   # HELLO, WORLD!

Timer decorator

Wraps a function to measure and print its execution time, preserving the original name with @wraps.

Example · python
import time
from functools import wraps

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_sum(n):
    return sum(range(n))

slow_sum(1_000_000)

Decorator with arguments

Implements a parametrised decorator factory that runs the wrapped function a configurable number of times.

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

@repeat(3)
def say(msg):
    print(msg)

say('Hello')
# Hello
# Hello
# Hello

Discussion

  • Be the first to comment on this lesson.