09 / 90

Day 09: Lists, dictionaries, frequency counts, and safe Git recovery

New material: lists and dictionaries, counting character frequencies (empty, repeated, and Unicode code-point cases), undoing an uncommitted edit versus reverting a committed change, and an independent text-statistics implementation. Spaced review reuses Day 08 invariants and Day 05 aliasing.

Self-Directed Learning & Python 480 active minutes (8 hours focused study)
01 120 min

Lists and dictionaries: ordered items and key–value counts

Agent-assisted practice: write your own prediction and observed output first; only then may you ask an AI agent to explain or review, and you must record that assistance in your evidence.

Prerequisites

Day 08 completed, including its independent check. Recovery: Day 08 (loops and invariants), Day 07 activity 1 (mutation versus rebinding); Day 07 is the review day for this block.

Learning Objective

Create and update lists and dictionaries, check membership, read missing keys safely with get, and predict aliasing when two names refer to the same list, including empty and Unicode cases.

Instructions

Study source: within this activity's existing reading/practice time, use Automate the Boring Stuff with Python, 3rd edition, Chapter 6; Practice Questions; Appendix B answers, then explain one connection to the local task in your own words. Keep the local exercise and acceptance checks; use its original explanation if the external source is unavailable. Spaced-review warm-up: from memory, state the counting invariant from Day 08 and explain why a = [1]; b = a; a.append(2) changes b. You will see the same aliasing with lists today.

New ideas: list(text) gives a list of code points. A list keeps items in order and append adds to its end. A dictionary maps keys to values; d[key] = value adds or replaces, key in d checks for a key, and d.get(key, 0) returns 0 instead of failing when the key is missing. Dictionaries remember insertion order.

Predict every printed line, then run:

chars = list("ñu猫")
print(chars, len(chars))
print(len("n\u0303u"), "n\u0303u" == "ñu")
seen = []
for ch in "abca":
    if ch not in seen:
        seen.append(ch)
print(seen)
ages = {}
ages["猫"] = 3
ages["犬"] = 5
ages["猫"] = ages["猫"] + 1
print(ages, len(ages), "猫" in ages, ages.get("鳥", 0))
alias = seen
alias.append("z")
print(seen)
print(list(""), {})

Practice & Prediction Log

Write predictions for all six printed lines, then record the observed output. Explain why len("n\u0303u") is 3, why seen keeps only the first occurrence of each character, and why appending through alias also changes seen.

Independent Mastery Criterion

All six lines are predicted before running, with each mismatch explained; you can explain get with a default, insertion order, the decomposed-character length, and list aliasing.

Authoritative Source Resources & Provenance

linking Copyright Al Sweigart; edition-specific reuse terms unverified linking only; no reproduction

Automate the Boring Stuff with Python, 3rd edition

Author: Al Sweigart | Original Source Link ↗

Relevant Section / Range: Chapter 6; Practice Questions; Appendix B answers

Verified Version & Date: Public edition checked 2026-11-01; moving pages may change

Selection Rationale:

Beginner teaching and answer-keyed practice before checking exact semantics in the Python reference; selected chapters only, not the book's entire automation stack.

Source Prerequisites:

No prior programming required for Chapter 1; later chapters assume its basic Python concepts.

Safe Fallback (Offline Resilience):

Use the original localized explanations, exercises and checks already present in this activity; no external account or purchase is required for that fallback.

Compared Candidate Sources & Selection Analysis (2)
The Python Tutorial ↗ compared_alternative [PSF License Version 2]

Guided Python syntax but assumes programming familiarity; paired with the beginner text rather than used as its replacement.

MIT OCW 6.0001 ↗ compared_alternative [CC BY-NC-SA 4.0]

Lectures and problem sets teach a broader CS1 course; the book offers shorter text-first entry and an answer appendix.

linking PSF License Version 2

The Python Tutorial: More Control Flow Tools

Author: Python Software Foundation | Original Source Link ↗

Relevant Section / Range: Sections 4.2–4.10 (for, range, defining functions); data structures are in Chapter 5 of the same tutorial

Verified Version & Date: Python 3.12 documentation; verified 2026-10-30

Selection Rationale:

Primary reference for Python iteration, functions, and containers.

Source Prerequisites:

Study Days 01-06 Python expression and filesystem fundamentals

Safe Fallback (Offline Resilience):

The lesson explains all required behavior locally and can be completed offline.

Compared Candidate Sources & Selection Analysis (2)
The Python Language Reference: Compound statements ↗ compared_alternative [PSF License Version 2]

Grammar-level definition of the same constructs; the tutorial chapter was selected for its guided pacing.

Lecture-paced coverage of the same control flow; deferred because the curriculum already drives the concepts through terminal drills.

02 120 min

Frequency counting with a dictionary and its invariant

Agent-assisted practice: write your own prediction and observed output first; only then may you ask an AI agent to explain or review, and you must record that assistance in your evidence.

Prerequisites

Today's activity 1. Recovery: Day 08 activity 1 (counting invariant) and today's activity 1 (dictionary get).

Learning Objective

Implement char_frequencies(text) and most_common(counts), state the dictionary invariant, and test empty, repeated, case-sensitive, emoji, and decomposed Unicode input at code-point granularity.

Instructions

Study source: within this activity's existing reading/practice time, use Automate the Boring Stuff with Python, 3rd edition, Chapter 7; Practice Questions; Appendix B answers, then explain one connection to the local task in your own words. Keep the local exercise and acceptance checks; use its original explanation if the external source is unavailable. Spaced review: this generalizes Day 08's single counter to one counter per distinct character.

Invariant: at the start of each iteration, counts maps every code point visited so far to the number of times it has been visited, and the values add up to the number of code points visited. most_common keeps the character with the highest count seen so far; a tie keeps the earlier character because only a strictly larger count replaces it.

Predict every line and write a trace table (ch / counts) for "banana" before running:

def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
def most_common(counts):
    best_char = None
    best_count = 0
    for ch in counts:
        if counts[ch] > best_count:
            best_char = ch
            best_count = counts[ch]
    return best_char
print(char_frequencies(""))
print(char_frequencies("banana"))
print(char_frequencies("猫猫犬"))
print(char_frequencies("aA"))
print(char_frequencies("😀😀"))
print(char_frequencies("e\u0301") == {"e": 1, "\u0301": 1})
print(most_common(char_frequencies("banana")))
print(most_common(char_frequencies("abab")))
print(most_common(char_frequencies("")))

Practice & Prediction Log

Submit your trace table for char_frequencies("banana"), predictions and observations for all nine printed lines, and one sentence each on why "aA" gives two keys, why "😀😀" gives a count of 2, and why the empty string gives {} and None.

Independent Mastery Criterion

Your trace table matches the reference; all nine lines are predicted or the mismatches are explained; you state the dictionary invariant and the tie rule, and you handle empty, repeated, case-sensitive, and Unicode cases correctly.

Authoritative Source Resources & Provenance

linking Copyright Al Sweigart; edition-specific reuse terms unverified linking only; no reproduction

Automate the Boring Stuff with Python, 3rd edition

Author: Al Sweigart | Original Source Link ↗

Relevant Section / Range: Chapter 7; Practice Questions; Appendix B answers

Verified Version & Date: Public edition checked 2026-11-01; moving pages may change

Selection Rationale:

Beginner teaching and answer-keyed practice before checking exact semantics in the Python reference; selected chapters only, not the book's entire automation stack.

Source Prerequisites:

No prior programming required for Chapter 1; later chapters assume its basic Python concepts.

Safe Fallback (Offline Resilience):

Use the original localized explanations, exercises and checks already present in this activity; no external account or purchase is required for that fallback.

Compared Candidate Sources & Selection Analysis (2)
The Python Tutorial ↗ compared_alternative [PSF License Version 2]

Guided Python syntax but assumes programming familiarity; paired with the beginner text rather than used as its replacement.

MIT OCW 6.0001 ↗ compared_alternative [CC BY-NC-SA 4.0]

Lectures and problem sets teach a broader CS1 course; the book offers shorter text-first entry and an answer appendix.

linking PSF License Version 2

The Python Tutorial: More Control Flow Tools

Author: Python Software Foundation | Original Source Link ↗

Relevant Section / Range: Sections 4.2–4.10 (for, range, defining functions); data structures are in Chapter 5 of the same tutorial

Verified Version & Date: Python 3.12 documentation; verified 2026-10-30

Selection Rationale:

Primary reference for Python iteration, functions, and containers.

Source Prerequisites:

Study Days 01-06 Python expression and filesystem fundamentals

Safe Fallback (Offline Resilience):

The lesson explains all required behavior locally and can be completed offline.

Compared Candidate Sources & Selection Analysis (2)
The Python Language Reference: Compound statements ↗ compared_alternative [PSF License Version 2]

Grammar-level definition of the same constructs; the tutorial chapter was selected for its guided pacing.

Lecture-paced coverage of the same control flow; deferred because the curriculum already drives the concepts through terminal drills.

03 120 min

Safe Git recovery: restore an uncommitted edit, revert a committed change

Agent-assisted practice: write your own prediction and observed output first; only then may you ask an AI agent to explain or review, and you must record that assistance in your evidence.

Prerequisites

Today's activities 1–2; Git installed. Recovery: Day 07 activity 3 and Day 08 activity 3 (git restore).

Learning Objective

In a disposable repository, choose the correct safe tool for each situation: git restore (or a saved copy) for an uncommitted edit, and git revert --no-edit HEAD for a committed change. Verify each result.

Instructions

Spaced review: Part A repeats the git restore pattern from Days 07–08 with today's frequency file.

New idea: git revert creates a new commit that undoes an earlier commit, so history is kept rather than rewritten. It works only on committed changes and refuses to run while the working tree has uncommitted changes to the affected file. That is why you must not commit a baseline, make an uncommitted edit, and then try git revert.

Use a new temporary directory for each part and predict every output first.

Part A, uncommitted edit, restored with Git:

cd "$(mktemp -d)"
git init -q
git config user.name "Learner"
git config user.email "[email protected]"
cat > freq.py <<'EOF'
def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
print(char_frequencies("猫猫犬"))
EOF
git add freq.py
git commit -q -m "Add char_frequencies"
python3 freq.py
printf 'print(char_frequencies(""))\n' >> freq.py
git status --short
python3 freq.py
git restore freq.py
git status --short
python3 freq.py

Part A alternative, a saved copy (no Git command needed to recover):

cd "$(mktemp -d)"
git init -q
git config user.name "Learner"
git config user.email "[email protected]"
cat > freq.py <<'EOF'
def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
print(char_frequencies("猫猫犬"))
EOF
git add freq.py
git commit -q -m "Add char_frequencies"
python3 freq.py
cp freq.py freq.py.saved
printf 'oops\n' >> freq.py
cp freq.py.saved freq.py
rm freq.py.saved
git status --short
python3 freq.py

Part B, committed change, reverted with a new commit:

cd "$(mktemp -d)"
git init -q
git config user.name "Learner"
git config user.email "[email protected]"
cat > freq.py <<'EOF'
def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
print(char_frequencies("猫猫犬"))
EOF
git add freq.py
git commit -q -m "Add char_frequencies"
python3 freq.py
printf 'print("debug")\n' >> freq.py
git commit -q -am "Add debug print"
python3 freq.py
git revert --no-edit HEAD > /dev/null
git log --format=%s
git diff HEAD~2 HEAD
git status --short
python3 freq.py

Part C, why the order matters: this shows git revert refusing while an uncommitted edit is present.

cd "$(mktemp -d)"
git init -q
git config user.name "Learner"
git config user.email "[email protected]"
cat > freq.py <<'EOF'
def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
print(char_frequencies("猫猫犬"))
EOF
git add freq.py
git commit -q -m "Add char_frequencies"
python3 freq.py
printf 'print("debug")\n' >> freq.py
git commit -q -am "Add debug print"
printf 'oops\n' >> freq.py
git revert --no-edit HEAD 2> /dev/null || echo "revert refused: uncommitted change present"
git status --short

Practice & Prediction Log

For each part, record your predictions and the observed output. Then answer: which command undoes an uncommitted edit, which undoes a committed change, what proves each recovery worked, and why git revert refused in Part C. The Unicode output {'猫': 2, '犬': 1} must be identical before the change and after recovery.

Independent Mastery Criterion

All three parts reproduce the reference output in a disposable repository; you correctly pair uncommitted edit with git restore or a saved copy and committed change with git revert --no-edit HEAD, show the verification for each, and explain the Part C refusal.

Authoritative Source Resources & Provenance

linking PSF License Version 2

The Python Tutorial: More Control Flow Tools

Author: Python Software Foundation | Original Source Link ↗

Relevant Section / Range: Sections 4.2–4.10 (for, range, defining functions); data structures are in Chapter 5 of the same tutorial

Verified Version & Date: Python 3.12 documentation; verified 2026-10-30

Selection Rationale:

Primary reference for Python iteration, functions, and containers.

Source Prerequisites:

Study Days 01-06 Python expression and filesystem fundamentals

Safe Fallback (Offline Resilience):

The lesson explains all required behavior locally and can be completed offline.

Compared Candidate Sources & Selection Analysis (2)
The Python Language Reference: Compound statements ↗ compared_alternative [PSF License Version 2]

Grammar-level definition of the same constructs; the tutorial chapter was selected for its guided pacing.

Lecture-paced coverage of the same control flow; deferred because the curriculum already drives the concepts through terminal drills.

04 120 min

Independent text-statistics implementation

Independent mastery check: no AI assistance and no reference answer until your evidence is submitted; declare your assistance honestly.

Prerequisites

Today's activities 1–3 with recorded evidence. Recovery: activity 2 (frequencies), Day 08 activity 2 (function contracts), Day 07 (review of conditions).

Learning Objective

Without assistance, implement text_stats(text) that reports code-point length, number of distinct code points, a frequency dictionary, and the most common code point, correct for empty, repeated, and Unicode text and safe to call repeatedly.

Instructions

Spaced review: this combines Day 08 loop invariants and functions with today's dictionaries. Do not open the reference answer or use AI until your evidence is submitted.

Specification for text_stats(text), which returns a dictionary with exactly these keys:
- "code_points": the number of Unicode code points in text (len(text)).
- "distinct": the number of different code points.
- "frequencies": a dictionary from each code point to its count, in first-seen order.
- "most_common": the code point with the highest count; on a tie, the one seen first; None for empty text.
Count Unicode code points exactly: no case folding and no normalization, so "e\u0301" is two code points. Each call must start from fresh state.

Before writing code, predict the full result for "", "abca", "😀😀a", and "naïve naïve", and the code_points, distinct, and most_common values for "e\u0301". Then implement, test, and finally write the loop invariant of your frequency loop and of your most-common loop.

Practice & Prediction Log

Submit: predictions for all five inputs, your text_stats code, the observed output, a check that calling text_stats("abca") twice gives equal results, and your two invariants. For each mismatch, write the recovery activity you will revisit.

Independent Mastery Criterion

Unaided: text_stats matches the reference output for all five inputs, including empty, repeated, emoji, accented, and decomposed text at code-point granularity; repeated calls are equal; both invariants are stated correctly; mismatches name a recovery activity.

Authoritative Source Resources & Provenance

linking PSF License Version 2

The Python Tutorial: More Control Flow Tools

Author: Python Software Foundation | Original Source Link ↗

Relevant Section / Range: Sections 4.2–4.10 (for, range, defining functions); data structures are in Chapter 5 of the same tutorial

Verified Version & Date: Python 3.12 documentation; verified 2026-10-30

Selection Rationale:

Primary reference for Python iteration, functions, and containers.

Source Prerequisites:

Study Days 01-06 Python expression and filesystem fundamentals

Safe Fallback (Offline Resilience):

The lesson explains all required behavior locally and can be completed offline.

Compared Candidate Sources & Selection Analysis (2)
The Python Language Reference: Compound statements ↗ compared_alternative [PSF License Version 2]

Grammar-level definition of the same constructs; the tutorial chapter was selected for its guided pacing.

Lecture-paced coverage of the same control flow; deferred because the curriculum already drives the concepts through terminal drills.