10 Practical Python Decorator Patterns to Supercharge Your Code
This article introduces ten useful Python decorator patterns—such as timing, logging, authentication, caching, input validation, retry, permission checks, type checking, singleton, and call counting—explaining their purpose, providing clear code examples, and showing how to apply them to enhance functions and classes.
Decorators are a powerful Python feature that let you modify, extend, or wrap functions and classes without changing their source code. A decorator is essentially a higher‑order function that receives a function (or class) as an argument and returns a new callable.
1. Timer Decorator (measure execution time)
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Function {func.__name__} executed in {end_time - start_time} seconds")
return result
return wrapper
@timer
def my_function():
# function implementation
pass
my_function()2. Logger Decorator (record call details)
def logger(func):
def wrapper(*args, **kwargs):
print(f"Calling function {func.__name__}, args: {args}, kwargs: {kwargs}")
result = func(*args, **kwargs)
print(f"Function {func.__name__} finished")
return result
return wrapper
@logger
def my_function():
# function implementation
pass
my_function()3. Authentication Decorator (protect functions)
def authenticate(func):
def wrapper(*args, **kwargs):
if is_authenticated():
return func(*args, **kwargs)
else:
raise Exception("Unauthorized access")
return wrapper
@authenticate
def protected_function():
# function implementation
pass
protected_function()4. Cache Decorator (memoize results)
def cache(func):
cached_results = {}
def wrapper(*args):
if args in cached_results:
return cached_results[args]
result = func(*args)
cached_results[args] = result
return result
return wrapper
@cache
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
fibonacci(10)5. Input‑Validation Decorator (type checking)
def validate_input(func):
def wrapper(*args, **kwargs):
for arg in args:
if not isinstance(arg, int):
raise ValueError("Arguments must be integers")
return func(*args, **kwargs)
return wrapper
@validate_input
def multiply(a, b):
return a * b
multiply(2, 3)6. Retry Decorator (automatic retries on failure)
import time
def retry(func):
def wrapper(*args, **kwargs):
max_retries = 3
for _ in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Function {func.__name__} failed: {e}")
time.sleep(1)
raise Exception(f"Function {func.__name__} failed after max retries")
return wrapper
@retry
def connect_to_server():
# function implementation
pass
connect_to_server()7. Permission‑Check Decorator (role‑based access)
def check_permission(permission):
def decorator(func):
def wrapper(*args, **kwargs):
if has_permission(permission):
return func(*args, **kwargs)
else:
raise Exception("Permission denied")
return wrapper
return decorator
@check_permission("admin")
def delete_user(user_id):
# function implementation
pass
delete_user(123)8. Type‑Check Decorator (input and output validation)
from functools import wraps
from typing import List
def type_check(func):
@wraps(func)
def wrapper(*args, **kwargs):
for arg in args:
if not isinstance(arg, int):
raise TypeError("Arguments must be integers")
result = func(*args, **kwargs)
if not isinstance(result, List):
raise TypeError("Return value must be a list")
return result
return wrapper
@type_check
def process_data(data):
# function implementation
pass
process_data([1, 2, 3])9. Singleton Decorator (ensure a single instance)
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class DatabaseConnection:
# class implementation
pass
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # True10. Counter Decorator (track call count)
def counter(func):
count = 0
def wrapper(*args, **kwargs):
nonlocal count
count += 1
print(f"Function {func.__name__} called {count} times")
return func(*args, **kwargs)
return wrapper
@counter
def my_function():
# function implementation
pass
my_function()
my_function()These ten decorator examples illustrate how to enhance functions and classes in Python, providing reusable patterns for timing, logging, security, caching, validation, resilience, permission control, type safety, singleton behavior, and usage statistics. Adapt and combine them as needed for your specific projects.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
