Profile Python functions with cProfile
Profile a Python program with cProfile, capture the stats in memory, and print a sorted performance report.
Python code
38 linesimport cProfile
import pstats
import io
def slow_function():
total = 0
for i in range(100000):
total += i ** 2
return total
def medium_function():
return sum(range(10000))
def fast_function():
return sum(range(100))
def main():
result1 = slow_function()
result2 = medium_function()
result3 = fast_function()
print(f"Results: {result1}, {result2}, {result3}")
if __name__ == "__main__":
profiler = cProfile.Profile()
profiler.enable()
main()
profiler.disable()
stream = io.StringIO()
stats = pstats.Stats(profiler, stream=stream)
stats.sort_stats("cumulative")
stats.print_stats()
print(stream.getvalue())
Output
Results: 333328333350000, 49995000, 4950
1000004 function calls in 0.097 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.097 0.097 {built-in method builtins.exec}
1 0.000 0.000 0.097 0.097 <string>:1(<module>)
1 0.000 0.000 0.097 0.097 /tmp/example.py:16(main)
1 0.040 0.040 0.082 0.082 /tmp/example.py:5(slow_function)
100000 0.042 0.000 0.042 0.000 {built-in method builtins.sum}
How it works
cProfile.Profile() creates a fresh profiler object that records every function call. Calling enable() starts recording and disable() stops it, wrapping only the main() call so external imports aren't counted. pstats.Stats reads the raw profile data and you can direct its text output into any file-like object (here an io.StringIO) instead of the default stdout. sort_stats('cumulative') orders functions by total time spent in them, making it easy to spot the slowest path. The printed report shows ncalls, tottime, and cumtime so you can separate each call's own cost from the cost of everything it calls.
Common mistakes
- Forgetting that `enable()`/`disable()` wrap the work — profile too much or too little code by misplacing them
- Printing `stats.print_stats()` without redirecting to a stream, which clutters the console output
- Not importing `io` before using `StringIO` as the stats destination
Variations
- Use `python -m cProfile script.py` from the command line for a quick run without modifying source
- Save stats to a file with `stats.dump_stats('out.prof')` and analyze later with `pstats` or SnakeViz
Real-world use cases
- Finding the bottleneck function in a batch job before optimizing the hot path.
- Measuring the cost of an expensive API call in a worker before adding caching.
- Comparing candidate implementations during a performance refactor to keep the fastest one.
Sponsored
More from Functions & basics
- Add Type Hints to Function Parameters and Return in Python easy
- Benchmark list append vs comprehension in Python easy
- Build a Context Manager in Python with contextlib.contextmanager easy
- Build a Progress Callback Function for Loops in Python easy
- Cache expensive function with lru_cache in Python easy
- Calculate Time Difference Across Time Zones in Python easy
Keep learning
Related tutorials and quizzes for this topic.