Common Python Decorators: Usage, Examples, and Implementation
This article introduces Python decorators, explains their syntax, and provides ten practical examples—including timing, caching, input validation, logging, error suppression, output validation, retry logic, visualization, debugging, and deprecation—complete with code snippets and usage guidance for data‑science and general development tasks.
Decorators are a powerful and flexible feature in Python that allow you to modify or enhance the behavior of functions or classes without changing their original code. A decorator is essentially a function that takes another function or class as an argument and returns a new function or class.
The syntax uses the @ symbol placed above the target function or class. Below are ten simple yet useful custom decorators.
@timer: Measure Execution Time
This decorator tracks the execution time of a function, helping identify performance bottlenecks.
<code>import time
def timer(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:.2f} seconds to execute.")
return result
return wrapper
@timer
def my_data_processing_function():
# Your data processing code here
pass
</code>@memoize: Cache Results
Useful for expensive functions, this decorator caches results to avoid redundant calculations.
<code>def memoize(func):
cache = {}
def wrapper(*args):
if args in cache:
return cache[args]
result = func(*args)
cache[args] = result
return result
return wrapper
@memoize
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
</code>@validate_input: Data Validation
Ensures function arguments meet specific criteria before execution.
<code>def validate_input(func):
def wrapper(*args, **kwargs):
# Your data validation logic here
if valid_data:
return func(*args, **kwargs)
else:
raise ValueError("Invalid data. Please check your inputs.")
return wrapper
@validate_input
def analyze_data(data):
# Your data analysis code here
pass
</code>@log_results: Log Output
Writes function results to a log file for debugging and monitoring.
<code>def log_results(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
with open("results.log", "a") as log_file:
log_file.write(f"{func.__name__} - Result: {result}\n")
return result
return wrapper
@log_results
def calculate_metrics(data):
# Your metric calculation code here
pass
</code>@suppress_errors: Graceful Error Handling
Prevents unexpected errors from crashing the entire workflow by catching exceptions and returning None .
<code>def suppress_errors(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Error in {func.__name__}: {e}")
return None
return wrapper
@suppress_errors
def preprocess_data(data):
# Your data preprocessing code here
pass
</code>@validate_output: Output Validation
Ensures the function's output conforms to expected standards before further processing.
<code>def validate_output(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if valid_output(result):
return result
else:
raise ValueError("Invalid output. Please check your function logic.")
return wrapper
@validate_output
def clean_data(data):
# Your data cleaning code here
pass
</code>@retry: Retry Execution
Retries a function upon encountering exceptions, with configurable attempts and delay.
<code>import time
def retry(max_attempts, delay):
def decorator(func):
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Attempt {attempts + 1} failed. Retrying in {delay} seconds.")
attempts += 1
time.sleep(delay)
raise Exception("Max retry attempts exceeded.")
return wrapper
return decorator
@retry(max_attempts=3, delay=2)
def fetch_data_from_api(api_url):
# Your API data fetching code here
pass
</code>@visualize_results: Automatic Visualization
Generates a visual representation of a function's result using Matplotlib.
<code>import matplotlib.pyplot as plt
def visualize_results(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
plt.figure()
# Your visualization code here
plt.show()
return result
return wrapper
@visualize_results
def analyze_and_visualize(data):
# Your combined analysis and visualization code here
pass
</code>@debug: Easy Debugging
Prints function name, arguments, and keyword arguments before execution.
<code>def debug(func):
def wrapper(*args, **kwargs):
print(f"Debugging {func.__name__} - args: {args}, kwargs: {kwargs}")
return func(*args, **kwargs)
return wrapper
@debug
def complex_data_processing(data, threshold=0.5):
# Your complex data processing code here
pass
</code>@deprecated: Mark Obsolete Functions
Issues a warning when a deprecated function is called.
<code>import warnings
def deprecated(func):
def wrapper(*args, **kwargs):
warnings.warn(f"{func.__name__} is deprecated and will be removed in future versions.", DeprecationWarning)
return func(*args, **kwargs)
return wrapper
@deprecated
def old_data_processing(data):
# Your old data processing code here
pass
</code>In summary, decorators are a versatile Python feature that can be applied to scenarios such as caching, logging, permission control, and more, simplifying development workflows and making code more robust.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
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.