Real Python Cheat Sheet
realpython.com
Python Decorators Examples
Learn more about decorators in Python in our in-depth tutorial at realpython.com/primer-on-python-decorators/
Using decorators Decorator not changing the decorated function
The normal way of using a decorator is by specifying it just before the definition of If you don’t want to change the decorated function, a decorator is simply a func-
the function you want to decorate: tion taking in and returning a function:
@decorator def name(func):
def f(arg_1, arg_2): # Do something with func
... return func
If you want to decorate an already existing function you can use the following syn- Example: Register a list of decorated functions.
tax:
def register(func):
f = decorator(f) """Register a function as a plug-in"""
PLUGINS[func.__name__] = func
return func
realpython.com 1
Python Decorators Examples
Basic decorator
Template for basic decorator that can modify the decorated function: Example: A timer decorator that prints the runtime of a function.
import functools import functools
import time
def name(func):
@functools.wraps(func) def timer(func):
def wrapper_name(*args, **kwargs): """Print the runtime of the function"""
# Do something before @functools.wraps(func)
value = func(*args, **kwargs) def wrapper_timer(*args, **kwargs):
# Do something after start_time = time.perf_counter()
return value value = func(*args, **kwargs)
return wrapper_name end_time = time.perf_counter()
run_time = end_time - start_time
print(f"Run time: {run_time:.4f} secs")
return value
return wrapper_timer
Decorator with arguments
If you want your decorator to take arguments, create a decorator factory that can Example: Rate limit your code by sleeping a given amount of seconds before call-
create decorators: ing the function.
import functools import functools
import time
def name(arg_1, ...):
def decorator_name(func): def slow_down(rate):
@functools.wraps(func) """Sleep before calling the function"""
def wrapper_name(*args, **kwargs): def decorator_slow_down(func):
# Do something before using arg_1, ... @functools.wraps(func)
value = func(*args, **kwargs) def wrapper_slow_down(*args, **kwargs):
# Do something after using arg_1, ... time.sleep(rate)
return value return func(*args, **kwargs)
return wrapper_name return wrapper_slow_down
return decorator_name return decorator_slow_down
realpython.com 2
Python Decorators Examples
Decorators that can optionally take arguments
If you want your decorator to be able to be called with or without arguments, you Example: Rate limit your code by sleeping an optionally given amount of seconds
need a dummy argument, _func, that is set automatically if the decorator is called before calling the function.
without arguments:
import functools
import functools import time
def name(_func=None, *, arg_1=val_1, ...): def slow_down(_func=None, *, rate=1):
def decorator_name(func): """Sleep before calling the function"""
@functools.wraps(func) def decorator_slow_down(func):
def wrapper_name(*args, **kwargs): @functools.wraps(func)
# Do something before using arg_1, ... def wrapper_slow_down(*args, **kwargs):
value = func(*args, **kwargs) time.sleep(rate)
# Do something after using arg_1, ... return func(*args, **kwargs)
return value return wrapper_slow_down
return wrapper_name
if _func is None:
if _func is None: return decorator_slow_down
return decorator_name else:
else: return decorator_slow_down(_func)
return decorator_name(_func)
Decorators that keep state
If you need your decorator to maintain state, use a class as a decorator: Example: Count the number of times the decorated function is called.
import functools import functools
class Name: class CountCalls:
def __init__(self, func): def __init__(self, func):
functools.update_wrapper(self, func) functools.update_wrapper(self, func)
self.func = func self.func = func
# Initialize state attributes self.num_calls = 0
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
# Update state attributes self.num_calls += 1
return self.func(*args, **kwargs) print(f"Call {self.num_calls}")
return self.func(*args, **kwargs)
realpython.com 3