Python Decorators Examples
Short, runnable programs that show python decorators in action. Read the explanation, press Run, then change the code and try your own ideas. New to the topic? Start with the Python Decorators lesson.
1Validate arguments before the function runs
The wrapper checks every positional argument first and raises a clear ValueError before the real function is called. The function itself stays free of checking code.
from functools import wraps
def positive_args(func):
@wraps(func)
def wrapper(*args):
for value in args:
if value <= 0:
raise ValueError(f"{func.__name__}: {value} must be positive")
return func(*args)
return wrapper
@positive_args
def rectangle_area(width, height):
return width * height
print(rectangle_area(4, 5))
try:
rectangle_area(4, -1)
except ValueError as error:
print("Rejected:", error)Expected output20
Rejected: rectangle_area: -1 must be positive
2Memoise with functools.cache
@cache stores each answer by its arguments. cache_info() reports how often a stored answer was reused (hits) and how often it had to be computed (misses).
from functools import cache
@cache
def shipping_cost(weight_kg):
print(f"computing for {weight_kg} kg")
return 4.5 + weight_kg * 1.25
print(shipping_cost(2))
print(shipping_cost(2))
print(shipping_cost(10))
print(shipping_cost(2))
print(shipping_cost.cache_info())Expected outputcomputing for 2 kg
7.0
7.0
computing for 10 kg
17.0
7.0
CacheInfo(hits=2, misses=2, maxsize=None, currsize=2)
3A decorator with an argument: deprecation warnings
deprecated("...") is called first and returns the real decorator. The message is remembered by the wrapper, which prints it on every call and then runs the old function.
from functools import wraps
def deprecated(replacement):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Warning: {func.__name__} is deprecated, use {replacement}")
return func(*args, **kwargs)
return wrapper
return decorator
@deprecated("total_price")
def old_total(prices):
return sum(prices)
def total_price(prices):
return round(sum(prices), 2)
print(old_total([4.5, 3.25]))
print(total_price([4.5, 3.25]))Expected outputWarning: old_total is deprecated, use total_price
7.75
7.75
4Stacking order: when does each layer run?
Decorators are applied bottom-up (inner first), but the wrappers run top-down (outer first). The printed lines show both orders.
def tag(name):
def decorator(func):
print(f"decorating with {name}")
def wrapper(*args, **kwargs):
print(f"enter {name}")
result = func(*args, **kwargs)
print(f"exit {name}")
return result
return wrapper
return decorator
@tag("outer")
@tag("inner")
def work():
print("working")
print("--- calling ---")
work()Expected outputdecorating with inner
decorating with outer
--- calling ---
enter outer
enter inner
working
exit inner
exit outer
5A decorator that registers functions
A decorator does not have to wrap anything. This one records each function in a dictionary and returns it unchanged, a pattern used by web frameworks to register routes and commands.
commands = {}
def command(name):
def decorator(func):
commands[name] = func
return func
return decorator
@command("hello")
def say_hello():
return "Hello there!"
@command("bye")
def say_bye():
return "See you soon!"
for name in sorted(commands):
print(name, "->", commands[name]())
print(say_hello())Expected outputbye -> See you soon!
hello -> Hello there!
Hello there!
6Format the result of many functions
One decorator changes the output of any function that returns a number. The functions keep calculating plain numbers, and the formatting lives in one place.
from functools import wraps
def as_currency(func):
@wraps(func)
def wrapper(*args, **kwargs):
amount = func(*args, **kwargs)
return f"${amount:,.2f}"
return wrapper
@as_currency
def order_total(prices, tax_rate=0.0):
return sum(prices) * (1 + tax_rate)
@as_currency
def shipping(weight_kg):
return 4.5 + weight_kg * 1.25
print(order_total([1200, 349.5], tax_rate=0.1))
print(order_total([19.99, 5]))
print(shipping(2))Expected output$1,704.45
$24.99
$7.00
Practise next
Python Decorators exercises → Back to the lesson
Python *args and **kwargs examplesPython Lambda Functions examplesPython Closures examplesPython Class Methods and Static Methods examples