Introduction
As Python developers, we’re always searching for ways to write more efficient, clean, and maintainable code. Enter decorators — a powerful Python feature that allows you to modify or enhance functions without changing their core implementation. In this article, we’ll dive deep into decorators through a real-world performance monitoring example.
What Are Decorators?
At its core, a decorator is a function that takes another function as an input and extends or modifies its behaviour. Think of it like a wrapper that can add functionality to existing code without modifying the original function.
Building a Performance Timer Decorator
Let’s create a practical decorator that measures the execution time of functions — a critical tool for performance optimisation.
import time
import functools
import random
def timer_decorator(func):
"""
A decorator that measures and logs the execution time of a function.
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Record the start time
start_time = time.time()
# Execute the original function
result = func(*args, **kwargs)
# Calculate and log execution time
end_time = time.time()
print(f"Function '{func.__name__}' took {end_time - start_time:.4f} seconds")
return result
return wrapper
# Real-World Application Examples
@timer_decorator
def slow_function():
"""
Simulate a time-consuming task by using sleep
"""
time.sleep(2)
print("Slow function completed")
@timer_decorator
def process_large_dataset(size=100000):
"""
Simulate processing a large dataset with sorting and filtering
"""
# Generate a large list of random numbers
data = [random.randint(1, 1000000) for _ in range(size)]
# Perform some expensive operations
sorted_data = sorted(data)
filtered_data = [x for x in sorted_data if x % 2 == 0]
return filtered_data
def main():
# Demonstrate the timer decorator
print("Timing a slow function:")
slow_function()
print("\nTiming a data processing function:")
result = process_large_dataset()
print(f"Processed {len(result)} even numbers")
if __name__ == "__main__":
main()
How the Decorator Works
- The
timer_decorator
wraps the original function - It records the start time before executing the function
- Runs the original function
- Calculates and prints the execution time
- Returns the original function’s result
Best Practices
- Always use
**@functools.wraps**
to preserve function metadata - Handle potential exceptions in your decorators
- Keep decorators focused on a single responsibility
- Use type hints for better readability and type checking
Conclusion
Decorators are a powerful Python feature that allows you to add functionality to functions seamlessly. By understanding and applying decorators, you can write more modular, maintainable, and insightful code.
Happy Coding! 🐍✨