Python Decorators
In this page:
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?
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
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
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
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
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())
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first: