Let’s build a simple decorator to time how long a function takes to execute.
Suppose we have a function that simulates a time-consuming operation:
import time
def database_operation_slow() -> None:
"""Simulates a slow database operation."""
time.sleep(2) # Simulate work Now, let’s create a time_it decorator
import time
def time_it(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs) # Call the original function
end = time.perf_counter()
duration = end - start
print(f"Function '{func.__name__}' took: {duration:.4f} seconds")
return result
return wrapper
# Applying the decorator
@time_it
def database_operation():
"""Simulates a database operation."""
time.sleep(1)
return "DB Operation Complete"
database_operation() How it works:
time_it is our decorator. It takes a function func as input.
Inside time_it, we define another function called wrapper. This function will eventually replace the original database_operation.
wrapper does three things:
- Records the time before calling the original function (
func). - Calls the original function (
func(*args, **kwargs)) and stores its result.*argsand**kwargsensure ourwrappercan handle any arguments the original function might take. - Records the time after, calculates the duration, prints it, and returns the result of the original function.
time_itreturns the wrapper function.
The @time_it syntax above database_operation is Python’s syntactic sugar for: time_it(database_operation)