Question presented to candidate: "A report endpoint written in Python has become slow, and a colleague wants to rewrite half of it. Before anyone changes code: how would you measure how slow it is, find out where the time and memory actually go, and prove that a fix helped?"
What a strong answer should cover:
- Measure before optimising: a repeatable benchmark, timed with
time.perf_counter()for a block ortimeit(many loops, several repeats, take the minimum) for small statements. - Profile to find the hot spot:
cProfile(a deterministic profiler,python -m cProfile -s cumulative app.py) and readingpstatscolumns:ncalls(withtotal/primitivefor recursion),tottimevscumtime. - Know the profiler families and their overhead: deterministic (cProfile) vs sampling profilers (py-spy, and
profiling.samplingin the standard library since Python 3.15) that can attach to a running process with little slowdown; line-level tools such as line_profiler. - Memory is separate:
sys.getsizeofis shallow,tracemallocrecords allocations, peaks and the source lines responsible. - Fix the algorithm or data structure first (a
setinstead of alistfor membership, caching withlru_cache, a generator instead of a giant list), then re-measure the same benchmark. - Caveats: noisy timings, warm-up, profiler overhead distorting tiny functions, and measuring on realistic data.
Clarifying questions expected:
- Is the problem latency of one request, throughput, or memory?
- Can we reproduce it locally with realistic data, or only in production (which favours a sampling profiler attached to the live process)?
Code / implementation expected: Optional โ a timeit comparison or a cProfile run and how to read its table.