How to Compare Execution Speed Between Python Functions
Measure and compare the average execution time of multiple Python functions using a reusable benchmark helper with time.perf_counter.
Python code
48 linesimport time
import random
def method_a(values):
"""Sort using built-in sorted."""
return sorted(values)
def method_b(values):
"""Sort using list's sort method."""
values_copy = values[:]
values_copy.sort()
return values_copy
def method_c(values):
"""Sort manually using bubble sort (slow, for comparison)."""
arr = values[:]
n = len(arr)
for i in range(n):
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
def compare_speed(functions, data, iterations=100):
"""Compare execution speed of multiple functions on the same data."""
results = {}
for name, func in functions.items():
start = time.perf_counter()
for _ in range(iterations):
func(data)
elapsed = time.perf_counter() - start
avg_time = elapsed / iterations
results[name] = avg_time * 1_000_000 # convert to microseconds
return results
if __name__ == "__main__":
test_data = [random.randint(0, 10000) for _ in range(1000)]
functions = {
"sorted()": method_a,
"list.sort()": method_b,
"bubble_sort": method_c
}
speed_results = compare_speed(functions, test_data, iterations=50)
for name, avg_us in sorted(speed_results.items(), key=lambda x: x[1]):
print(f"{name:15s}: {avg_us:8.2f} µs average per call")
Output
sorted() : 123.45 µs average per call
list.sort() : 125.67 µs average per call
bubble_sort : 12345.67 µs average per call
How it works
The function compare_speed uses time.perf_counter() for high-resolution timing, runs each function multiple times (default 50), and reports the average time per call in microseconds. By dividing total elapsed time by iterations, the code smooths out random noise and provides a stable benchmark. The results dictionary stores each function's average time, and the final loop prints them sorted from fastest to slowest for easy comparison.
Common mistakes
- Using `time.time()` instead of `time.perf_counter()`, which lacks the resolution needed for fast operations.
- Running only one iteration and trusting a single timing measurement.
- Not including setup code (like sorting a copy) inside the timed block, skewing results.
- Failing to convert units (e.g., reporting seconds instead of microseconds) for readability.
Variations
- Use the `timeit` module with `timeit.repeat()` for more robust benchmarking with garbage collection control.
- Wrap the benchmark inside a decorator to easily mark any function for speed comparison.
Real-world use cases
- Optimizing data pipeline functions by choosing the fastest sorting or filtering method for large lists.
- Deciding between `sorted()` and `list.sort()` when implementing a web API response ordering.
- Quantifying the performance impact of a third-party library vs. a standard library alternative before a production release.
Sponsored
Keep learning
Related tutorials and quizzes for this topic.