Decorators for Timing Functions: Measuring Execution Time
A decorator in Python is a function that wraps another function to modify its behavior. One useful application of decorators is to measure the execution time of functions. This can be useful for performance monitoring or profiling. Below is an example of how to create a decorator that measures the execution time of a function.
1. Basic Timing Decorator
This decorator will measure the time it takes for a function to execute and print the result.
import time# Timing decoratordeftiming_decorator(func):defwrapper(*args,**kwargs): start_time = time.time()# Record start time result =func(*args,**kwargs) end_time = time.time()# Record end timeprint(f"Execution time of {func.__name__}: {end_time - start_time:.4f} seconds")return resultreturn wrapper# Example function to measure@timing_decoratordefslow_function(): time.sleep(2)# Simulating a time-consuming operationreturn"Done"# Call the functionslow_function()
Output:
2. Decorator with Arguments
If you want to add functionality like logging the time for a list of functions or conditional execution, you can add parameters to the decorator.
Output:
3. Timing Decorator for Multiple Functions
You can use a decorator to time multiple functions without repeating the timing logic.
Output:
4. Using functools.wraps for Preserving Function Metadata
When using decorators, the metadata of the wrapped function (like its name and docstring) may be lost. To avoid this, use functools.wraps() to preserve the original function's attributes.
Output:
5. Decorator for Asynchronous Functions
If your function is asynchronous, you can also use a timing decorator with asyncio.
Output:
6. Using Time in Nanoseconds
To measure the execution time with more precision, you can use time.perf_counter() which provides a higher-resolution timer.
Output:
7. Timing Function with Return Value
The decorator can also return the function’s result after logging the execution time.
Output:
8. Using Timing Decorators with Function Arguments
You can also pass arguments into the decorator, like logging the time for specific types of functions.
Output:
9. Decorator for Profiling Multiple Functions
Use the decorator for profiling multiple functions in your code.
Output:
10. Combining Multiple Decorators
You can combine timing decorators with other decorators, for example, logging.
Output:
By using decorators to measure execution time, you can efficiently monitor the performance of your functions, especially when working with time-consuming tasks. The decorator pattern is a powerful tool in Python, and this technique helps keep the code clean and reusable.
import time
# Timing decorator with an argument
def timing_decorator(log_time=False):
def decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
if log_time:
print(f"Execution time of {func.__name__}: {end_time - start_time:.4f} seconds")
return result
return wrapper
return decorator
# Example function
@timing_decorator(log_time=True)
def fast_function():
time.sleep(1)
fast_function()
Execution time of fast_function: 1.0001 seconds
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:.4f} seconds")
return result
return wrapper
@timing_decorator
def function_one():
time.sleep(0.5)
@timing_decorator
def function_two():
time.sleep(1)
function_one()
function_two()
function_one took 0.5003 seconds
function_two took 1.0002 seconds
import time
import functools
def timing_decorator(func):
@functools.wraps(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:.4f} seconds")
return result
return wrapper
@timing_decorator
def example_function():
"""This is an example function."""
time.sleep(1)
example_function()
print(example_function.__name__) # Output: example_function
print(example_function.__doc__) # Output: This is an example function.
example_function took 1.0001 seconds
example_function
This is an example function.
import asyncio
import time
def timing_decorator(func):
async def wrapper(*args, **kwargs):
start_time = time.time()
result = await func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
return result
return wrapper
@timing_decorator
async def async_function():
await asyncio.sleep(2)
# Running the async function
asyncio.run(async_function())
async_function took 2.0001 seconds
import time
def timing_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
print(f"{func.__name__} took {end_time - start_time:.6f} seconds")
return result
return wrapper
@timing_decorator
def slow_function():
time.sleep(1)
slow_function()
slow_function took 1.000123 seconds
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:.4f} seconds")
return result
return wrapper
@timing_decorator
def add(a, b):
return a + b
print(add(3, 5))
add took 0.0001 seconds
8
import time
def timing_decorator(message):
def decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{message}: {func.__name__} took {end_time - start_time:.4f} seconds")
return result
return wrapper
return decorator
@timing_decorator("Execution Time")
def slow_function():
time.sleep(3)
slow_function()