← Back to Python Course | Chapter 11: Advanced Python | Lesson 3 of 12

Python Decorators

What is a Decorator?

A decorator is a function that wraps another function, adding behavior before or after the original runs, without permanently modifying the original function's own code -- it takes a function in and returns a (usually new, wrapped) function out.

Example: What is a Decorator?

python
def shout(func):
    def wrapper():
        print(func().upper())
    return wrapper

@shout
def greet():
    return "hello"

greet()

Designing a Basic Decorator

Applying a decorator manually just means calling it with your target function and using whatever it returns: 'wrapped = my_decorator(original_function)' -- understanding this manual form is what makes the @ shorthand's actual behavior clear rather than feeling like magic.

Example: Designing a Basic Decorator

python
def shout(func):
    def wrapper():
        print(func().upper())
    return wrapper

def greet():
    return "hello"

wrapped = shout(greet)
wrapped()

Decorating with Arguments

Because the function being decorated might accept any combination of arguments, a general-purpose wrapper collects them with *args and **kwargs and forwards them unchanged to the original function -- without this, a decorator would only work on functions with one exact, fixed signature.

Example: Decorating with Arguments

python
def log(func):
    def wrapper(*args, **kwargs):
        print("Calling", func.__name__)
        return func(*args, **kwargs)
    return wrapper

@log
def add(a, b):
    return a + b

print(add(2, 3))

The @ Syntax

Writing '@my_decorator' directly above a function definition is exactly equivalent to writing 'my_function = my_decorator(my_function)' right after it -- the @ syntax is pure convenience, not a different mechanism underneath.

Example: The @ Syntax

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

@shout
def greet():
    return "hi"

print(greet())  # same as greet = shout(greet)

Multiple Decorators

Stacking multiple decorators on one function applies them from the bottom up -- the decorator closest to the function wraps it first, and each decorator above that wraps the result of the one below it, so execution order matters when the decorators interact.

Example: Multiple Decorators

python
def bold(func):
    def wrapper():
        return "**" + func() + "**"
    return wrapper

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

@bold
@shout
def greet():
    return "hi"

print(greet())

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.