Challenge 3: Identify the Bottleneck — Possible Solution ==================================================================== import cProfile def slow_helper(): return sum(range(100)) # small, individually fast computation def process(): results = [] for _ in range(1000): results.append(slow_helper()) return results cProfile.run("process()") # ncalls is the column that makes this pattern obvious: slow_helper's # ncalls would read 1000, immediately showing it was called far more # often than any other function in the profile. Its individual tottime # per call would look tiny (a small, fast computation, per the # challenge's own description), but because ncalls is so high, the # helper's OVERALL contribution to total runtime (visible by comparing # its tottime to process()'s own tottime, or by checking its share of # process()'s cumtime) can still be significant — the cost comes from # being called too often, not from any single call being slow. Output (abbreviated, exact timings will vary): 1004 function calls in 0.002 seconds ncalls tottime percall cumtime percall filename:lineno(function) 1 0.001 0.001 0.002 0.002 script.py:7(process) 1000 0.001 0.000 0.001 0.000 script.py:4(slow_helper) WHY THIS WORKS AS AN ANSWER ------------------------------ process() reuses the chapter's own described scenario directly — a loop calling slow_helper() 1000 times and collecting results into a list, using Course 1, Chapter 6's .append() pattern. cProfile.run("process()") reuses the chapter's own programmatic profiling call exactly, applied to process() as a whole so the profiler captures both process() itself AND every call it makes to slow_helper(), rather than profiling slow_helper() in isolation (which would hide the "called 1000 times" pattern entirely, since a single call in isolation would just look fast). The comment identifies ncalls specifically, per the chapter's own column definitions, as the column that makes a many-cheap-calls pattern visible — tottime alone, read per call (or via the percall column), would show slow_helper as fast, potentially misleadingly suggesting nothing is wrong with it. It's only by also noticing ncalls = 1000 that the real story — a fast function paying a real cumulative cost purely from being invoked so often — becomes clear, exactly the "called too often vs individually slow" distinction the challenge asks to articulate.