← Back to course
Python 11-12 / Week 01 / Wednesday
3/6
Week 01 · Back at the Terminal

Wednesday

Sim Lab: Comet's dict prototype
// Review fast, trace before you run, and name the three kinds of error
⏱ about 30 min

Wednesday: Sim Lab: Comet's Dict Prototype

Comet arrives early with a printout. Last night she wrote the sample log as a list of dicts, one dict per sample.

"Four samples, five keys each," she says. "Let's run it and move on to the rover!"

Wren reads the printout line by line. "What does the evidence say?" he asks. "How do we know every dict has every key? A dict will hold whatever we type into it."

Nova draws four boxes on the wall, one for each stage of the build. "How can I help?" she asks. "Build it in stages, and predict before every run."

Comet grins and hands you the keyboard. "Lead programmer, stage one is yours."

Sim Lab: a prototype sample log

A prototype is a quick first version, built to try an idea. Comet's idea is to store each sample as a dict with the keys label, kind, grams, row and col.

The four samples in this table are made-up data from the FieldSim story. Row and col give each sample's spot on the test field.

labelkindgramsrowcol
S01basalt4202
S02quartz1824
S03clay6530
S04mica745
  1. Stage 1: type describe() and one sample, then run.
  2. Stage 2: add all four samples in a list, with a loop.
  3. Stage 3: add a total line.
  4. Stage 4: break it on purpose, read the error and fix it.
# samples_v1.py
# Comet's first prototype: each sample is a dict.


def describe(sample):
    return (f"{sample['label']} {sample['kind']} {sample['grams']} g "
            f"at ({sample['row']}, {sample['col']})")


s01 = {"label": "S01", "kind": "basalt", "grams": 42, "row": 0, "col": 2}
print(describe(s01))
PREDICT STAGE 1
  • Read the question.
  • Tap your answer.
What does stage 1 show?

Stage 2: all four samples

Replace the last two lines of stage 1 with the list below and a loop. Keep describe() as it is.

# samples_v1.py
# Comet's first prototype: each sample is a dict.


def describe(sample):
    return (f"{sample['label']} {sample['kind']} {sample['grams']} g "
            f"at ({sample['row']}, {sample['col']})")


samples = [
    {"label": "S01", "kind": "basalt", "grams": 42, "row": 0, "col": 2},
    {"label": "S02", "kind": "quartz", "grams": 18, "row": 2, "col": 4},
    {"label": "S03", "kind": "clay", "grams": 65, "row": 3, "col": 0},
    {"label": "S04", "kind": "mica", "grams": 7, "row": 4, "col": 5},
]

for s in samples:
    print(describe(s))
PREDICT STAGE 2
  • Read the question.
  • Tap your answer.
What is the third line?
How many times does print(describe(s)) run?

Stage 3: a total

Add these lines at the end of samples_v1.py to find the total grams of all four samples.

# samples_v1.py
# Comet's first prototype: each sample is a dict.


def describe(sample):
    return (f"{sample['label']} {sample['kind']} {sample['grams']} g "
            f"at ({sample['row']}, {sample['col']})")


samples = [
    {"label": "S01", "kind": "basalt", "grams": 42, "row": 0, "col": 2},
    {"label": "S02", "kind": "quartz", "grams": 18, "row": 2, "col": 4},
    {"label": "S03", "kind": "clay", "grams": 65, "row": 3, "col": 0},
    {"label": "S04", "kind": "mica", "grams": 7, "row": 4, "col": 5},
]

for s in samples:
    print(describe(s))

total = 0
for s in samples:
    total += s["grams"]
print(f"Total: {total} g")
PREDICT STAGE 3
  • Read the question.
  • Tap your answer.
What is the new last line?

Stage 4: Comet's typo

Here is what happened in Comet's first draft. She typed one key in the S04 dict as "gram" instead of "grams".

Make the same typo in your file, run it, and read the message from the bottom up.

# samples_v1.py
# Comet's first prototype: each sample is a dict.


def describe(sample):
    return (f"{sample['label']} {sample['kind']} {sample['grams']} g "
            f"at ({sample['row']}, {sample['col']})")


samples = [
    {"label": "S01", "kind": "basalt", "grams": 42, "row": 0, "col": 2},
    {"label": "S02", "kind": "quartz", "grams": 18, "row": 2, "col": 4},
    {"label": "S03", "kind": "clay", "grams": 65, "row": 3, "col": 0},
    {"label": "S04", "kind": "mica", "gram": 7, "row": 4, "col": 5},
]

for s in samples:
    print(describe(s))
S01 basalt 42 g at (0, 2)
S02 quartz 18 g at (2, 4)
S03 clay 65 g at (3, 0)
Traceback (most recent call last):
  File "samples_v1.py", line 18, in <module>
    print(describe(s))
          ~~~~~~~~^^^
  File "samples_v1.py", line 6, in describe
    return (f"{sample['label']} {sample['kind']} {sample['grams']} g "
                                                  ~~~~~~^^^^^^^^^
KeyError: 'grams'

KeyError means a dictionary has no such key. The S04 dict has a key called gram, but describe() asks for grams.

This is a run-time error: it happens while the program runs, after three lines have already printed. An exception, like this KeyError, is one kind of run-time error.

READ THE KEYERROR
  • Read the question.
  • Tap your answer.
How many sample lines print before the error?
Which kind of error is this?
Which key does the last line of the message name?
WHY THIS EXERCISEdescribe() asked for the key grams, and the S04 dict did not have it.
At your computer
1. Save stage 1 as samples_v1.py in your fieldsim folder. Predict, then run it.
2. Change it to stage 2. Predict the third line, then run it.
3. Add the stage 3 total lines. Predict, then run it.
4. Change "grams" to "gram" in the S04 dict. Run it and find the KeyError on the last line.
5. Fix the typo and run it again. Check that all four lines and the total print.

Wren writes one note on his clipboard. Nothing stopped Comet from making a dict without a grams key. Python only noticed when describe() asked for it.

Next week the crew tries a class: one blueprint that every sample is built from. Tomorrow you will sort errors into three kinds.

← Tuesday