Latticework

Command Palette

Search for a command to run...

Python

Decorators

16 min

Explanation

Functions in Python are values — you can pass one as an argument, return one from another function, or wrap one to add behavior. A decorator is a function that takes a function and returns a new (usually wrapped) function.

def shout(func):
    def wrapper(name):
        return func(name).upper()
    return wrapper

def greet(name):
    return f"hello, {name}"

greet = shout(greet)   # manually "decorating"
print(greet("ada"))     # HELLO, ADA
Try it

@shout above 'def greet' is exactly equivalent to writing 'greet = shout(greet)' right after defining it — pure syntax sugar, nothing magic.

Loading editor…
Explanation

Real decorators need to wrap functions with ANY signature, so the wrapper almost always uses *args, **kwargs to pass everything through unchanged:

def log_call(func):
    def wrapper(*args, **kwargs):
        print(f"calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

That's the shape you'll reuse for almost every decorator you write: accept anything, do something extra, then call the original function with exactly what was passed in.

Exercise

Write a decorator `double_result(func)` that wraps `func` so the wrapped function's return value is doubled.

Exercise

Write a decorator `require_positive(func)` that wraps `func` so that if any positional argument is negative, the wrapper returns the string 'invalid' instead of calling `func`.

Quiz

What does writing @my_decorator directly above a function definition do?

Checkpoint

You can write a decorator that wraps a function's behavior, using *args/**kwargs to pass arguments through unchanged.