Session 8 - Dictionaries

Session 8 of the Python Fundamentals series, covered in depth. A dictionary maps a key to a value, and the session covers creating one, looking up with d[key] and with the safer d.get(key, default), adding and updating entries, checking for a key with in, len(), and looping over the keys and over .items(). It then replaces a long if/elif chain with a single lookup, tallies counts, and uses numeric keys. The traps are a KeyError on a missing key, indexing a dictionary as though it were a list, and duplicate keys overwriting one another. Every snippet and error message was copied verbatim from CPython 3.12.

Subject: Python Fundamentals · 95 slides · code lesson

Open the interactive version of this deck · Homework for this lesson

What this lesson covers

The lesson, slide by slide

1. Dictionaries

Title

Python Fundamentals - Session 8

Look things up by name, not by position

2. What you will be able to do

Objectives

Lists hold items in order; dictionaries hold pairs you look up by key. By the end you can:

  1. Create a dictionary of key -> value pairs.
  2. Look up a value with d[key], and safely with d.get(key, default).
  3. Add, update, and check keys with in.
  1. Loop over keys and over .items().
  2. Replace a long if/elif chain with a single dictionary lookup.
  3. Avoid the KeyError and 'index like a list' traps.

3. What survived from Session 7 - for Loops & Lists?

Warm-up

Discussion prompt

Before we open Session 8 - Dictionaries: without looking back, what was the main idea of Session 7 - for Loops & Lists, and what could you do by the end of it that you could not do before?

Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.

Answer:

That session covers lists and zero-based indexing, len(), the for loop, range() in three forms, append(), membership testing, and computing over a list.

4. Key maps to Value

Section

Part 1

5. A dictionary maps keys to values

Concept

A dictionary stores key -> value pairs. You look a value up by its key, like finding a word's meaning in a real dictionary.

dictionary (dict) — A collection of key: value pairs in curly braces. Each key is unique and maps to one value: {"France": "Paris"}.

6. Break it if you can: A dictionary maps keys to values

Counterexample

Discussion prompt

A dictionary stores key -> value pairs. You look a value up by its key, like finding a word's meaning in a real dictionary.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

7. Making one: curly braces

Concept

Write pairs as key: value, separated by commas, inside { }.

{"France": "Paris", "Japan": "Tokyo"} maps each country to its capital.

8. By analogy: Making one: curly braces

Analogy

Discussion prompt

Explain Making one: curly braces by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

Write pairs as key: value, separated by commas, inside { }.

9. Why is this step legal: Read the output

Explain it to yourself

Discussion prompt

In A capitals dictionary this move is made:

Read the output

Why is that legal? Name the rule or definition it rests on before you read on.

Hint: If you can only say "because that is what you do", the rule is the thing to go and find.

Answer:

Verified by execution: prints the pairs in braces.

10. A capitals dictionary

Worked example

capital = {"France": "Paris", "Japan": "Tokyo"}
print(capital)

Two pairs, one dictionary

Why: Each country (key) maps to its capital (value).

Read the output

Why: Verified by execution: prints the pairs in braces.

keyvalue
FranceParis
JapanTokyo

11. Fill in: value for A capitals dictionary

Comparison

Comparison matrix

From A capitals dictionary: refill the value column from what you know. The rest of the table is as it appeared.

keyvalue
FranceParis
JapanTokyo

12. Look up by key

Concept

capital["Japan"] returns the value for that key - "Tokyo". The key goes in square brackets, just like list indexing.

But the 'index' here is a name, not a position.

13. Teach it back: Look up by key

Explain it

Discussion prompt

Explain Look up by key to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

capital["Japan"] returns the value for that key - "Tokyo". The key goes in square brackets, just like list indexing.

14. Reading a value

Worked example

capital = {"France": "Paris", "Japan": "Tokyo"}
print(capital["Japan"])

The key selects the value

Why: "Japan" maps to "Tokyo".

Read the output

Why: Verified by execution: Tokyo.

expressionvalue
capital["Japan"]Tokyo

15. Draw the shape of it: Reading a value

Blank canvas

Draw it

Draw what Reading a value just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

16. Labeled drawers

Intuition

Picture a wall of drawers, each with a name label. A list numbers the drawers 0, 1, 2; a dict names them 'France', 'Japan'.

To get a value you read the label, not count positions. That is the whole difference - and the whole point.

17. Keys are unique

Concept

Each key appears once. Assigning to a key that already exists replaces its value rather than adding a second copy.

18. Something is wrong here: duplicate keys overwrite

Anomaly

Predict first

A student writes this, and it looks reasonable:

Writing the same key twice, expecting both.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: A key can hold only one value, so the second "a": 2 replaces the first.

Use different keys for different pairs.

Why: A key can hold only one value, so the second "a": 2 replaces the first. The 1 is simply lost.

19. Trap: duplicate keys overwrite

Trap

The trap

Writing the same key twice, expecting both.

d = {"a": 1, "a": 2}
print(d)

The later value wins

Why: A key can hold only one value, so the second "a": 2 replaces the first. The 1 is simply lost.

you writeactual
{"a": 1, "a": 2}{'a': 2}

The fix

Use different keys for different pairs.

d = {"a": 1, "b": 2}
print(d)

Two distinct keys, two values

Why: Now both survive. Real output: {'a': 1, 'b': 2}. If you truly need several values under one key, store a list as the value.

keyskept
a, bboth

20. Looking Up Safely

Section

Part 2

21. A missing key is a KeyError

Concept

Asking for a key that is not there with d[key] crashes with a KeyError.

This is the dict version of an index-out-of-range: you asked for something that does not exist.

22. Something is wrong here: looking up a missing key

Anomaly

Predict first

A student writes this, and it looks reasonable:

Brazil is not a key

It is wrong. Say what breaks — and say it before you turn the page.

Correct: d[key] demands the key exist. It does not, so Python raises a KeyError and stops.

Use .get() with a fallback for keys that might be missing.

Why: d[key] demands the key exist. It does not, so Python raises a KeyError and stops.

23. Trap: looking up a missing key

Trap

The trap

No entry for Brazil.

capital = {"France": "Paris"}
print(capital["Brazil"])

Brazil is not a key

Why: d[key] demands the key exist. It does not, so Python raises a KeyError and stops.

you writeresult
capital["Brazil"]KeyError: 'Brazil'

The fix

Use .get() with a fallback for keys that might be missing.

capital = {"France": "Paris"}
print(capital.get("Brazil", "unknown"))

.get returns the fallback instead of crashing

Why: capital.get("Brazil", "unknown") is "unknown" because the key is absent. Real output: unknown.

callvalue
get("Brazil", "unknown")unknown

24. Break it on purpose: looking up a missing key

Break the constraint

Discussion prompt

The rule this trap just fixed:

Use .get() with a fallback for keys that might be missing.

Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?

Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.

Answer:

d[key] demands the key exist. It does not, so Python raises a KeyError and stops.

25. .get(key, default)

Concept

d.get(key, default) returns the value if the key exists, or the default you supply if it does not - never a crash.

If you omit the default, a missing key gives back None instead of an error.

26. Present vs missing

Worked example

capital = {"France": "Paris", "Japan": "Tokyo"}
print(capital.get("Japan", "unknown"))
print(capital.get("Brazil", "unknown"))

Present key returns its value

Why: Japan is there, so get returns Tokyo.

Missing key returns the default

Why: Verified by execution: Tokyo, then unknown.

keyin dict?get result
JapanyesTokyo
Brazilnounknown

27. What each one costs: Present vs missing

Trade off

Comparison matrix

From Present vs missing: every row here is a choice with a cost. Fill the get result column, then say which row you would actually pick and what you give up for it.

keyin dict?get result
JapanyesTokyo
Brazilnounknown

28. in tests the keys

Concept

"France" in capital checks whether that key exists - True or False. It looks at keys, not values.

29. Is the key there?

Worked example

capital = {"France": "Paris", "Japan": "Tokyo"}
print("France" in capital)
print("Spain" in capital)

in scans the keys

Why: France is a key; Spain is not.

Read the output

Why: Verified by execution: True then False. Use this before a d[key] to avoid a KeyError.

expressionvalue
"France" in capitalTrue
"Spain" in capitalFalse

30. Adding & Updating

Section

Part 3

31. Assign to add or update

Concept

d[key] = value either adds a new pair (if the key is new) or updates the value (if the key already exists).

One syntax does both - Python decides based on whether the key is already present.

32. Restore the missing line: Add a new country

Fill the middle

Fill in the blanks

From Add a new country — one line has had its right-hand side removed. Put it back.

capital = "Madrid"
capital["Spain"] = ___
print(capital)

Why: capital["Spain"] is what everything below it consumes, so the wrong expression here fails later and somewhere else. Verified by execution: now includes 'Spain': 'Madrid'.

33. Add a new country

Worked example

capital = {"France": "Paris", "Japan": "Tokyo"}
capital["Spain"] = "Madrid"
print(capital)

Spain is new, so a pair is added

Why: The dict grows to three pairs.

Read the output

Why: Verified by execution: now includes 'Spain': 'Madrid'.

beforeafter
2 pairs3 pairs (+ Spain: Madrid)

34. Why is this step legal: Japan already exists, so its value is replaced

Explain it to yourself

Discussion prompt

In Update an existing value this move is made:

Japan already exists, so its value is replaced

Why is that legal? Name the rule or definition it rests on before you read on.

Hint: If you can only say "because that is what you do", the rule is the thing to go and find.

Answer:

Same key, new value - no second Japan is created.

35. Update an existing value

Worked example

capital = {"Japan": "Tokyo"}
capital["Japan"] = "Kyoto"
print(capital)

Japan already exists, so its value is replaced

Why: Same key, new value - no second Japan is created.

Read the output

Why: Verified by execution: {'Japan': 'Kyoto'}.

keyoldnew
JapanTokyoKyoto

36. Inspect it line by line: Update an existing value

Error analysis

Annotate

Walk the callouts on Update an existing value. Each one is a place this is easy to get subtly wrong.

  • Same key, new value - no second Japan is created.
  • Verified by execution: {'Japan': 'Kyoto'}.

37. len() counts the pairs

Concept

len(d) is how many key -> value pairs the dictionary holds.

38. How many pairs?

Worked example

capital = {"France": "Paris", "Japan": "Tokyo"}
print(len(capital))

Count the pairs

Why: Two keys, so two pairs.

Read the output

Why: Verified by execution: 2.

dictlen
2 pairs2

39. Looping Over a Dict

Section

Part 4

40. for key in d

Concept

Looping over a dictionary gives you its keys, one per pass. Use the key to look up its value inside.

41. Why is this step legal: Look up the value with the key

Explain it to yourself

Discussion prompt

In Loop over the keys this move is made:

Look up the value with the key

Why is that legal? Name the rule or definition it rests on before you read on.

Hint: If you can only say "because that is what you do", the rule is the thing to go and find.

Answer:

Verified by execution: France -> Paris, Japan -> Tokyo.

42. Loop over the keys

Worked example

capital = {"France": "Paris", "Japan": "Tokyo"}
for country in capital:
    print(country, "->", capital[country])

country takes each key

Why: France, then Japan.

Look up the value with the key

Why: Verified by execution: France -> Paris, Japan -> Tokyo.

countrycapital[country]
FranceParis
JapanTokyo

43. .items() gives key and value

Concept

for k, v in d.items(): hands you the key and the value together each pass - no separate lookup needed.

44. Loop over pairs

Worked example

capital = {"France": "Paris", "Japan": "Tokyo"}
for country, city in capital.items():
    print(country, "->", city)

Two loop variables, one per part

Why: country gets the key, city gets the value, each pass.

Read the output

Why: Verified by execution: same result, cleaner than looking up inside.

countrycity
FranceParis
JapanTokyo

45. Keys are the index

Intuition

Everything you did with list positions, you now do with dict keys: look up with d[key], test with in, walk with a for.

The mental swap is simply: 'which number?' becomes 'which name?'.

46. The Payoff

Section

Part 5

47. A dict replaces a long if/elif chain

Concept

When an if/elif chain just maps inputs to outputs, a dictionary does the same job in one lookup.

The pairs live in data, not in code - easier to read, and easy to extend by adding one more entry.

48. Restore the missing line: Canned replies as a dict

Fill the middle

Fill in the blanks

From Canned replies as a dict — one line has had its right-hand side removed. Put it back.

replies = "hi"
msg = ___
print(replies.get(msg, "I don't get it"))

Why: msg is what everything below it consumes, so the wrong expression here fails later and somewhere else. replies[msg] would be the whole if/elif chain collapsed into data.

49. Canned replies as a dict

Worked example

replies = {"hi": "Hey!", "bye": "See ya!"}
msg = "hi"
print(replies.get(msg, "I don't get it"))

One lookup instead of many ifs

Why: replies[msg] would be the whole if/elif chain collapsed into data.

.get supplies the else branch

Why: Verified by execution: prints Hey! An unknown msg would give the fallback.

msgreply
hiHey!
xyz (missing)I don't get it

50. Tallying counts with a dict

Concept

A dict is perfect for counting: the item is the key, its running count is the value.

tally[item] = tally.get(item, 0) + 1 reads as 'current count (or 0) plus one'.

51. Predict the next row: Counting votes

Pattern

Predict first

The table runs: red | {red: 1} · blue | {red: 1, blue: 1} · red | {red: 2, blue: 1} · red | {red: 3, blue: 1}

In Counting votes, given the rows so far: what is the next one — the row where v is blue?

Correct: blue | {red: 3, blue: 2}

vtally after
red{red: 1}
blue{red: 1, blue: 1}
red{red: 2, blue: 1}
red{red: 3, blue: 1}
blue{red: 3, blue: 2}

Why: The relationship between the columns, not the individual numbers, is what generates the next row. So it starts at 0 + 1 = 1, then climbs on repeats.

52. Counting votes

Worked example

votes = ["red", "blue", "red", "red", "blue"]
tally = {}
for v in votes:
    tally[v] = tally.get(v, 0) + 1
print(tally)

First time a color appears, get returns 0

Why: So it starts at 0 + 1 = 1, then climbs on repeats.

Trace the tally

Why: Verified by execution: {'red': 3, 'blue': 2}.

vtally after
red{red: 1}
blue{red: 1, blue: 1}
red{red: 2, blue: 1}
red{red: 3, blue: 1}
blue{red: 3, blue: 2}

53. Fill in: tally after for Counting votes

Comparison

Comparison matrix

From Counting votes: refill the tally after column from what you know. The rest of the table is as it appeared.

vtally after
red{red: 1}
blue{red: 1, blue: 1}
red{red: 2, blue: 1}
red{red: 3, blue: 1}
blue{red: 3, blue: 2}

54. Finish it with less help: Build a dict in a loop

Faded example

Fill in the blanks

Build a dict in a loop, with the scaffolding fading: two lines are gone now — fill both.

pairs = [("pen", 2), ("book", 9)]
prices = cost
for item, cost in pairs:
prices[item] = ___
print(prices)

Why: Reproducing these unaided, rather than reading them, is what tells you the method has transferred. prices[item] = cost inserts one entry per pass.

55. Build a dict in a loop

Worked example

pairs = [("pen", 2), ("book", 9)]
prices = {}
for item, cost in pairs:
    prices[item] = cost
print(prices)

Start empty, add each pair

Why: prices[item] = cost inserts one entry per pass.

Read the output

Why: Verified by execution: {'pen': 2, 'book': 9}.

itemprices after
pen{pen: 2}
book{pen: 2, book: 9}

56. Where the cost goes: Build a dict in a loop

Cost model

Annotate

In Build a dict in a loop, before reading the notes: mark where the time actually goes. Which line dominates?

  • prices[item] = cost inserts one entry per pass.
  • Verified by execution: {'pen': 2, 'book': 9}.

57. Pitfalls & Keys

Section

Part 6

58. Something is wrong here: indexing a dict like a list

Anomaly

Predict first

A student writes this, and it looks reasonable:

Using a position number on a dict.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: A dict has no positions. Python looks for a key 0, does not find one, and raises a KeyError.

A dict has no positions. Python looks for a key 0, does not find one, and raises a KeyError.

Why: A dict has no positions. Python looks for a key 0, does not find one, and raises a KeyError.

59. Trap: indexing a dict like a list

Trap

The trap

Using a position number on a dict.

capital = {"France": "Paris"}
print(capital[0])

0 is treated as a key, not a position

Why: A dict has no positions. Python looks for a key 0, does not find one, and raises a KeyError.

you writeresult
capital[0]KeyError: 0

The fix

Use an actual key.

capital = {"France": "Paris"}
print(capital["France"])

Look up by name

Why: The key is "France", not a number. Real output: Paris. Dicts are indexed by key, lists by position.

you writevalue
capital["France"]Paris

60. Which of these survive contact with Session 8 - Dictionaries?

Two truths and a lie

Sort into buckets

Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.

Holds up
A dictionary stores key -> value pairs. You look a value up by its key, like finding a word's meaning in a real dictionary.; Write pairs as key: value, separated by commas, inside { }.; capital["Japan"] returns the value for that key - "Tokyo". The key goes in square brackets, just like list indexing.
Breaks
Writing the same key twice, expecting both.; Using a position number on a dict.
sound
These are stated as this lesson states them — each one survives the edge cases Session 8 - Dictionaries puts it through.
flawed
Each of these is lifted from a trap in this deck: reasonable-sounding, and wrong in a way that only shows up once you rely on it.

61. Keys can be numbers too

Concept

Keys are not limited to strings - numbers work as keys as well: {1: "A", 2: "B"}.

Even so, d[1] looks up the key 1, not the item at position 1. There is still no such thing as a position in a dict.

62. Numeric keys

Worked example

grades = {1: "A", 2: "B"}
print(grades[1])

1 is a key here

Why: grades[1] returns the value stored under the key 1.

Read the output

Why: Verified by execution: A.

keyvalue
1A
2B

63. When to use a dict vs a list

Concept

Use a list when order and position matter, or items are all the same role (a queue of scores).

Use a dict when you look things up by a name or id (a country's capital, a user's score).

64. Dictionaries in Practice

Section

Part 7

65. Loop over values with .values()

Concept

d.values() gives just the values. You can total them with sum(d.values()) or loop over them directly.

66. Total the values

Worked example

scores = {"Ana": 84, "Ben": 55, "Cy": 110}
print(sum(scores.values()))

sum adds every value

Why: 84 + 55 + 110.

Read the output

Why: Verified by execution: 249.

valuessum
84, 55, 110249

67. Draw the shape of it: Total the values

Blank canvas

Draw it

Draw what Total the values just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

68. Finding the biggest value

Concept

To find which key has the largest value, loop over .items() and track the best so far - the same 'running maximum' idea as with lists.

69. Teach it back: Finding the biggest value

Explain it

Discussion prompt

Explain Finding the biggest value to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

To find which key has the largest value, loop over .items() and track the best so far - the same 'running maximum' idea as with lists.

70. Predict the next row: Who scored highest?

Pattern

Predict first

The table runs: Ana, 84 | Ana 84 · Ben, 55 | Ana 84

In Who scored highest?, given the rows so far: what is the next one — the row where name, s is Cy, 110?

Correct: Cy, 110 | Cy 110

name, sbest so far
Ana, 84Ana 84
Ben, 55Ana 84
Cy, 110Cy 110

Why: The relationship between the columns, not the individual numbers, is what generates the next row. Each time a higher score appears, update both.

71. Who scored highest?

Worked example

scores = {"Ana": 84, "Ben": 55, "Cy": 110}
best = ""
best_score = -1
for name, s in scores.items():
    if s > best_score:
        best_score = s
        best = name
print(best, best_score)

Track the best name and score seen so far

Why: Each time a higher score appears, update both.

Trace the running best

Why: Verified by execution: Cy 110.

name, sbest so far
Ana, 84Ana 84
Ben, 55Ana 84
Cy, 110Cy 110

72. Watch it run: Who scored highest?

Pattern

Step through it

Step through Who scored highest? one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: name, s is Ana, 84
  2. Step 2: name, s is Ben, 55
  3. Step 3: name, s is Cy, 110

73. A value can be a list

Concept

Values are not limited to single items - a value can be a whole list, which is how you group things under a key.

{"A": ["Ana", "Al"], "B": ["Ben"]} maps each group to its members.

74. By analogy: A value can be a list

Analogy

Discussion prompt

Explain A value can be a list by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

Values are not limited to single items - a value can be a whole list, which is how you group things under a key.

75. Grouping with lists as values

Worked example

roster = {"A": ["Ana", "Al"], "B": ["Ben"]}
print(roster["A"])
print(len(roster["A"]))

The value is a list you can use normally

Why: roster["A"] is a list, so len() and indexing work on it.

Read the output

Why: Verified by execution: ['Ana', 'Al'] then 2.

keyvalue (a list)len
A['Ana', 'Al']2
B['Ben']1

76. Inspect it line by line: Grouping with lists as values

Error analysis

Annotate

Walk the callouts on Grouping with lists as values. Each one is a place this is easy to get subtly wrong.

  • roster["A"] is a list, so len() and indexing work on it.
  • Verified by execution: ['Ana', 'Al'] then 2.

77. Keys unique, values anything

Intuition

Two rules capture dicts: every key is unique, and each value can be anything - a number, a string, even a list or another dict.

That freedom is why dictionaries model so much real-world data: a profile, an inventory, a scoreboard.

78. Break it if you can: Keys unique, values anything

Counterexample

Discussion prompt

Two rules capture dicts: every key is unique, and each value can be anything - a number, a string, even a list or another dict.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

79. Restore the missing line: A menu by lookup

Fill the middle

Fill in the blanks

From A menu by lookup — one line has had its right-hand side removed. Put it back.

menu = input("Pick 1-3: ")
choice = ___
print(menu.get(choice, "invalid"))

Why: choice is what everything below it consumes, so the wrong expression here fails later and somewhere else. menu.get looks the option up, with a fallback for bad input.

80. A menu by lookup

Worked example

The user types 2, then 9:

menu = {"1": "Play", "2": "Score", "3": "Quit"}
choice = input("Pick 1-3: ")
print(menu.get(choice, "invalid"))

The choice is the key

Why: menu.get looks the option up, with a fallback for bad input.

Read the output

Why: Verified by execution: 2 gives Score; 9 gives invalid.

choiceresult
2Score
9invalid

81. What each one costs: A menu by lookup

Trade off

Comparison matrix

From A menu by lookup: every row here is a choice with a cost. Fill the result column, then say which row you would actually pick and what you give up for it.

choiceresult
2Score
9invalid

82. Patterns & Checks

Section

Part 8

83. Using a dictionary

Pattern

1. Look up with d[key], or d.get(key, default) if it might be missing

Why: d[key] crashes on a missing key; get returns your fallback instead.

2. Add or update with d[key] = value

Why: Same syntax adds a new pair or replaces an existing one.

3. Check keys with in; walk with for k, v in d.items()

Why: in tests keys; items() gives key and value together.

4. To count, use d[item] = d.get(item, 0) + 1

Why: The tally pattern - key is the thing, value is its running count.

84. Why is this step legal: Both: use in to test membership, len() for size

Explain it to yourself

Discussion prompt

In Dict vs list, at a glance this move is made:

Both: use in to test membership, len() for size

Why is that legal? Name the rule or definition it rests on before you read on.

Hint: If you can only say "because that is what you do", the rule is the thing to go and find.

Answer:

For a list, in checks values; for a dict, in checks keys.

85. Dict vs list, at a glance

Pattern

Ordered items, same role -> list

Why: scores = [55, 84], accessed by position.

Look up by name/id -> dict

Why: capital = {"France": "Paris"}, accessed by key.

Both: use in to test membership, len() for size

Why: For a list, in checks values; for a dict, in checks keys.

86. Where this shows up: Session 8 - Dictionaries

Real world

Discussion prompt

Outside this lesson: where does Session 8 - Dictionaries actually turn up? Name one concrete situation — a job, a piece of software someone ships, a decision somebody has to make — and say which part of Dict vs list, at a glance is doing the work in it.

Hint: Vague is the failure mode here. "Engineering" is not a situation; "deciding whether this build is fast enough to ship" is.

Answer:

Session 8 of the Python Fundamentals series, in depth. Dictionaries map a key to a value: creating them, looking up with d[key] and the safe d.get(key, default), adding and updating, checking keys with in, len(), looping over keys and over .items(), replacing a long if/elif chain with one lookup, tallying counts, and numeric keys.

87. Check: lookup

Check

Read the value for the key.

ages = {"Sam": 12, "Ana": 15}
print(ages["Ana"])
keyvalue
Ana?

Check your understanding

What does this print?

  • A. 15 (correct)
  • B. 12
  • C. Ana
  • D. KeyError

Answer: A

Why: ages["Ana"] returns the value stored under the key Ana, which is 15. Verified by execution.

Why B tempts people
12 is Sam's value, not Ana's.
Why C tempts people
Ana is the key you looked up; d[key] returns the value, not the key.
Why D tempts people
Ana is a real key, so there is no error.

88. Check: missing key

Check

The key is not present.

ages = {"Sam": 12}
print(ages["Ana"])
key present?d[key]
no?

Check your understanding

What happens?

  • A. KeyError: 'Ana' (correct)
  • B. It prints None
  • C. It prints 0
  • D. It prints Ana

Answer: A

Why: d[key] requires the key to exist. Ana is not in the dict, so Python raises a KeyError. ages.get("Ana", 0) would return 0 instead. Verified by execution.

Why B tempts people
d[key] crashes on a missing key; only .get() (with no default) returns None.
Why C tempts people
There is no automatic 0 - that would be .get("Ana", 0).
Why D tempts people
It never prints the key; it errors before printing.

89. Check: get with default

Check

Key missing, but a default is given.

ages = {"Sam": 12}
print(ages.get("Ana", 0))
key present?result
no?

Check your understanding

What does this print?

  • A. 0 (correct)
  • B. KeyError
  • C. None
  • D. 12

Answer: A

Why: .get returns the default (0) when the key is missing, instead of crashing. Verified by execution.

Why B tempts people
.get never raises KeyError - that is the whole point of using it.
Why C tempts people
A default was supplied (0), so it returns 0, not None.
Why D tempts people
12 is Sam's value; Ana is not in the dict, so the default is used.

90. Check: in tests keys

Check

Does in look at keys or values?

capital = {"France": "Paris"}
print("Paris" in capital)
is Paris a key?value
no (it is a value)?

Check your understanding

What does this print?

  • A. False (correct)
  • B. True
  • C. Paris
  • D. KeyError

Answer: A

Why: in checks the keys, and Paris is a value, not a key. The only key is France, so the result is False. Verified by execution.

Why B tempts people
Paris is a value, not a key; in only searches keys.
Why C tempts people
in returns a bool, not the string.
Why D tempts people
in never raises an error - it just returns True or False.

91. Check: update

Check

Same key assigned twice.

d = {"x": 1}
d["x"] = 5
print(d)
keyfinal value
x?

Check your understanding

What does this print?

  • A. {'x': 5} (correct)
  • B. {'x': 1, 'x': 5}
  • C. {'x': 6}
  • D. {'x': 1}

Answer: A

Why: Assigning to an existing key replaces its value, so x becomes 5. A key cannot appear twice. Verified by execution.

Why B tempts people
A dict cannot hold the same key twice - the second assignment overwrites the first.
Why C tempts people
= replaces the value; it does not add 1 + 5.
Why D tempts people
The value was updated to 5, so it is no longer 1.

92. Check: the tally

Check

Trace the counts.

t = {}
for x in ["a", "b", "a"]:
    t[x] = t.get(x, 0) + 1
print(t)
xt
a?
a?

Check your understanding

What does this print?

  • A. {'a': 2, 'b': 1} (correct)
  • B. {'a': 1, 'b': 1}
  • C. {'a': 3}
  • D. {'a': 2, 'b': 2}

Answer: A

Why: a appears twice and b once, so the tally is a: 2, b: 1. get(x, 0) starts each new key at 0. Verified by execution.

Why B tempts people
a is counted twice, so its count is 2, not 1.
Why C tempts people
b also appears once and gets its own key; a is counted twice, not three times.
Why D tempts people
b appears only once, so its count is 1, not 2.

93. Fill in: t for Check: the tally

Comparison

Comparison matrix

From Check: the tally: refill the t column from what you know. The rest of the table is as it appeared.

xt
a?
a?

94. Connect it up: Session 8 - Dictionaries

Connect it up

Draw it

One page, no notation unless you need it: draw how these connect — Key maps to Value · Looking Up Safely · Adding & Updating · Looping Over a Dict · The Payoff · Pitfalls & Keys. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.

95. What you can do now

Recap

A dictionary maps keys to values. Look up by key, add/update by assignment, and loop over keys or .items().

You wantUse
a value by keyd[key]
safe lookupd.get(key, default)
add / updated[key] = value
is the key there?key in d
each pairfor k, v in d.items()
count thingsd[x] = d.get(x, 0) + 1

Dicts are indexed by name, not position, and d[missing] is a KeyError - use .get when unsure. Next session we package code into reusable functions.

Sources

  1. Python 3 Tutorial - Dictionaries
  2. Python 3 Library Reference - Mapping Types (dict.get, items)
  3. All snippets and error messages executed and copied from CPython 3.12. — Author verification run, 2026-07-15 (Python Fundamentals series, Session 8).

Want this taught 1-on-1? Alexander tutors Python Fundamentals — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108