Skip to main content
Learning Center
Python Programming

Performance and Resilience

Profiling, Complexity, and Memory

Use measurements to find the real constraint, then choose an algorithm and representation that fit the workload.

Lesson 3 of 6 in the recommended order · About 25 min (estimate)

On this page

Outcome

Interpret a profile and replace repeated linear lookup with an indexed representation.

Why it matters

At this level, code is judged by how safely it changes under load, failure, and team ownership. The technique in this lesson makes an important boundary visible enough to test and review.

Concept

Complexity predicts growth; profiling shows where this workload spends time. Measure representative inputs, separate CPU from waiting, and include peak memory in the decision.

Read the code

def join_rows(agencies, awards):
    agency_by_id = {row["id"]: row["name"] for row in agencies}
    return [
        {"agency": agency_by_id.get(row["agency_id"], "Unknown"), "value": row["value"]}
        for row in awards
    ]

print(join_rows([{"id": 2, "name": "Transit"}], [{"agency_id": 2, "value": 8}]))

Read from the public behavior inward: identify the input boundary, the decision, and the observable result before studying syntax.

Predict the output

Predict the exact output before running the example.

Check your prediction
[{'agency': 'Transit', 'value': 8}]

It prints one joined record for Transit. Building the index once avoids scanning every agency for every award.

Modify the code

Change one valid input into the nearest invalid or overloaded case. Write down which layer should reject it and what the caller should observe.

Review the change

Keep the failure at the narrowest boundary that owns the rule. Preserve a stable return value or exception contract so callers do not need to inspect implementation details.

Debug the bug

A microbenchmark with tiny cached data can reward the wrong change. Use representative volume, warmup, multiple samples, and an end-to-end guardrail.

Try it yourself

Complete the focused implementation and run its deterministic checks.

Loading this exercise…

Practical challenge (optional)

Compare a nested-loop join and indexed join at three input sizes; report runtime and peak memory without claiming universal results.

Sign in to track your progress on this exercise.

AI collaboration

Checkpoint

  1. What different questions do complexity analysis and a profiler answer?
  2. What time-and-memory tradeoff does the agency index introduce?
  3. Why can a tiny, warm-cache microbenchmark recommend the wrong change?
Answers
  1. Complexity predicts how resource use grows; profiling measures where a representative run actually spends its resources.
  2. It replaces repeated linear scans with average constant-time dictionary lookup while retaining an additional dictionary in memory.
  3. It may omit realistic volume, I/O, allocation, cold-start, and end-to-end costs, so the measured bottleneck differs from production.

Sign in to track your progress on this exercise.

Summary and next step

You made the boundary explicit, predicted its behavior, tested a deterministic implementation, and examined its failure mode. Continue to the next lesson to combine this technique with a wider application or production constraint.

learning.goultergroup.com

The interactive parts of this page have not loaded. Reading and links still work; reload the page to try again.