Loop through the list, dict-access each item
Once you have a list of dicts — and you will, every single time you unpack an API response — the natural next move is to loop. Walk every item in the list, pull a few fields out of each, do something. AI writes this constellation of moves a staggering number of times in any given file.
The pattern feels obvious in hindsight, but it has a couple of subtle traps that catch new readers.
The mental model: for X in Y["key"] is two operations
Read this line:
for team in org["teams"]:
...
There are two things happening:
org["teams"]evaluates first. You're reaching into the dict to get the value at"teams". That value is a list.- The
for ... in ...then walks that list, one item at a time. On each iteration, the loop variableteamholds one element of the list — which, since the list contained dicts, is itself a dict.
So inside the loop body, team is one team dict, not the whole
org, not the list. The keys you can read from it (team["name"],
team["members"]) are whatever keys live on that inner shape — not
the keys of the outer org.
This is the reading habit to build: at the top of every loop body, ask yourself "what kind of thing is the loop variable right now?"
The worked example
The editor on the right has a small organization with two teams:
org = {
"name": "promptdojo",
"teams": [
{"name": "eng", "members": ["maya", "marcus"]},
{"name": "ops", "members": ["riley"]},
],
}
for team in org["teams"]:
print(team["name"], "→", len(team["members"]))
Trace what happens:
- Iteration 1:
teamis{"name": "eng", "members": ["maya", "marcus"]}. Soteam["name"]is"eng"andlen(team["members"])is2. Printseng → 2. - Iteration 2:
teamis{"name": "ops", "members": ["riley"]}. Soteam["name"]is"ops"andlen(team["members"])is1. Printsops → 1.
Notice: the two team["name"] reads return different values. The
key name is identical, but it's a different dict each time. That
trips up beginners reading nested code — they sometimes think
team["name"] "means" something fixed.
Where AI specifically gets this wrong
Two patterns to watch for when Cursor writes nested-walk code:
-
Looping the wrong layer. AI sometimes writes
for team in org:when it meantfor team in org["teams"]:. The first one walks the keys of the outer dict ("name","teams"), not the list of teams. The bug looks confusing because the loop runs without crashing — it just hands you strings instead of dicts on each iteration. -
Reading a key that doesn't exist on the inner shape. Cursor writes
team["url"]because it remembered "url" from a different data structure earlier in the file. The keys onteamare only"name"and"members". You getKeyError: 'url'. Defense: when reading AI code, eyeball the actual data shape before trusting the keys it reaches for.
Two more shapes you'll see this week
- List of lists:
for row in rows: for cell in row: ...— typical for CSV or table data. - Dict of dicts:
for user_id, user in users.items(): ...— when the outer container is keyed by ID, not ordered.
Both are the same idea: loop the outer, reach into each item by its shape. The reading habit is identical.
One more name for a shape you now know: a graph
Later in the course (agent workflows, retrieval) you'll hear the word graph — things connected to other things. It sounds like a new data structure. It isn't. In working code, a small graph is usually just two lists of dicts:
nodes = [
{"id": "invoice-104", "type": "invoice"},
{"id": "acme", "type": "client"},
]
edges = [
{"from": "invoice-104", "rel": "billed_to", "to": "acme"},
]
The nodes list says what things exist; the edges list says how
they connect, and "rel" names the connection. To answer "who is this
invoice billed to?" you loop edges and dict-access each item —
exactly the walk you just learned. No library, no database. When a
tool later hands you a "knowledge graph," look for these two lists
under the hood.
Run the editor. Watch the two lines print, one per team.