Introduction to Python Decorators
Python decorators are a powerful and versatile tool in Python programming, allowing developers to modify or extend the behavior of functions or methods without modifying the original code. A decorator is essentially a function that wraps another function, dynamically altering its behavior.
Decorators are commonly used to perform logging, enforce access control, measure execution time, and much more, making them an essential concept for writing elegant and reusable Python code. This article dives into dozens of useful decorator applications and provides simple examples to demonstrate their utility.
Basic Syntax of a Decorator
Below is the simplest example of a Python decorator:
def my_decorator(func): def wrapper(): print("Something is happening before the function is executed.") func() print("Something is happening after the function is executed.") return wrapper @my_decorator def say_hello(): print("Hello!") say_hello()
Output:
Something is happening before the function is executed. Hello! Something is happening after the function is executed.
Commonly Used Decorators With Examples
1. Logging Decorator
import logging def log_decorator(func): def wrapper(*args, **kwargs): logging.info(f"Running {func.__name__} with arguments {args} and {kwargs}") return func(*args, **kwargs) return wrapper @log_decorator def add(a, b): return a + b print(add(5, 3))
2. Timing Function Execution
import time def timing_decorator(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"{func.__name__} took {end_time - start_time} seconds to execute") return result return wrapper @timing_decorator def slow_function(): time.sleep(2) print("Finished sleeping") slow_function()
3. Authentication Check
def authenticate(user_role): def decorator(func): def wrapper(*args, **kwargs): if user_role != "admin": print("Unauthorized access") return return func(*args, **kwargs) return wrapper return decorator @authenticate("admin") def delete_user(): print("User deleted") delete_user()
4. Singleton Decorator
def singleton(cls): instances = {} def get_instance(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return get_instance @singleton class Database: def __init__(self): print("Connecting to the database") db1 = Database() db2 = Database() print(db1 is db2) # True
Building an App Example Using Decorators
Let’s build a small application to demonstrate the power and utility of decorators in a real-world context:
Flask-like Framework Simulating API Authentication and Logging
# Decorators for the app def authenticate(token): def decorator(func): def wrapper(*args, **kwargs): if token != "valid-token": return "403 Forbidden: Invalid Authentication Token" return func(*args, **kwargs) return wrapper return decorator def log_request(func): def wrapper(*args, **kwargs): print(f"Request made to: {func.__name__}") return func(*args, **kwargs) return wrapper # Simulated API Endpoints @log_request @authenticate("valid-token") def get_data(): return {"data": "This is some secured data"} @log_request @authenticate("invalid-token") def get_admin_data(): return {"data": "Admin data: Confidential"} # Simulated App Execution print(get_data()) # Successful request print(get_admin_data()) # Unauthorized request
Conclusion
Python decorators are a powerful feature that can be used to simplify and organize code, enforce security, manage resource usage, and much more. This article has covered a large variety of decorator use cases, from basic to advanced. Try using decorators in your next Python project to see how they can improve your code!