Lesson 1 of 0
In Progress

Unit 5 – Teachers Guide

Unit 5 · Teacher's Guide | Knowledge Pillars · Code Quest
📚 Teacher's Guide Code Quest · Coding Fundamentals

Unit 5 · Data Power — Lists, Dicts, Tuples & Strings

Your day-to-day companion for delivering Unit 5 — pacing, standards, lesson plans, misconceptions, differentiation, and a Python error appendix. Unit 5 is where students learn to shape data. They get power-user list skills, meet the dictionary (the data structure they'll use most for the rest of their career), and build a working contact-management app that mirrors how every CRM and address book on the planet stores data.

📊 5 Lessons + Capstone
⏱️ 8–10 class periods
🎓 Florida Course #9009200

👋 Welcome — How to Use This Guide

This Teacher's Guide is your day-to-day companion for delivering Unit 5 of the Code Quest curriculum. Unit 5 is the unit that turns students from "people who can write programs" into "people who can shape data." It picks up after Unit 4's modular code thinking and assumes students are fluent with variables, conditionals, loops, basic lists, functions, parameters & returns, scope, and the SDLC. Unit 5 deepens lists, introduces the dictionary (the data structure students will use most for the rest of their career), adds tuples and string manipulation, and culminates in the Contact Vault — a working contact-management app that combines all four data structures.

What this guide contains

  • A pacing guide showing how Unit 5 maps to roughly 8–10 class periods. Lessons 1–3 are 50 min; Lesson 4 is 45 min; Lesson 5 is a 2-day capstone.
  • A standards & exam crosswalk. Unit 5 is the home of standard 04.03 (sorting/filtering data sets) and provides full coverage of 07.05 (variable types) at depth across all four data structures.
  • A unit vocabulary glossary with all 20 key terms students will encounter — Python's data-structure vocabulary in one place.
  • Five detailed lesson plans using the same 7-section format from prior guides.
  • An appendix covering data-structure-specific Python errors: KeyError, TypeError: 'tuple' object does not support item assignment, AttributeError on string methods used incorrectly, and the silent bug of mutating a list while iterating it.

How each lesson plan is structured

Same 7-section format used in prior units:

  • At-a-Glance — objective, time, materials, vocabulary, standards box
  • Lesson Flow — a 45–50 minute breakdown: warm-up, instruction, guided practice, lab, exit ticket
  • Watch For — the 3–5 most common student misconceptions and how to address each
  • Differentiation — early finishers and struggling students
  • Discussion Prompts — questions to spark whole-class conversation
  • Real-World Connections — answering "why does this matter?"
  • Lesson-Specific Vocabulary — terms introduced or reinforced

How to read this in conjunction with the student lessons

  • Before class: read this lesson plan (5–10 min) and skim the student HTML, noting the interactive widgets (the Path Explorer in L3 is especially worth previewing — it's the unit's marquee tool)
  • During class: follow the lesson flow; the student HTML is the textbook + lab
  • After class: grade Knowledge Checks and labs against this guide's expectations
💡 Unit 5 is the most "Pythonic" unit of the year. Lists, dicts, tuples, and strings are Python's bread and butter — the four built-in data structures every Python program uses. Unit 5 doesn't introduce a "biggest concept" the way functions in Unit 4 did. Instead, it introduces a wide breadth of new tools (about 15 new methods across data types) and asks students to combine them. The capstone (Contact Vault) is where everything clicks. Don't rush — the student who internalizes dict.get(), list.append(), tuple unpacking, and "text".split() by the end of Unit 5 is the student who flies through Units 6–10.

🗺️ Unit 5 Overview

The big picture

Unit 5 is "Data Power." Students learn the four built-in Python data structures — list, dict, tuple, string — and the manipulation skills that make data useful. Lesson 1 takes lists from "I can iterate" to "power user" with methods, slicing, and pattern recognition. Lesson 2 introduces dictionaries — the most-used data structure in modern Python. Lesson 3 combines them: looping dicts and navigating nested structures (dicts inside lists, lists inside dicts). Lesson 4 covers tuples — Python's immutable cousin to the list. Lesson 5 covers string manipulation, then the capstone (Contact Vault) integrates all four.

What students learn

  • Use the seven essential list methods: .append(), .insert(), .remove(), .pop(), .extend(), .index(), .count(), plus the in operator
  • Slice lists and strings with [start:stop:step] notation
  • Apply the three iteration patterns: filter (build a results list), map (transform each item), accumulate (sum/count across)
  • Create, read, update, and delete dictionary entries
  • Use .get() for safe lookups (returns default instead of crashing on missing keys)
  • Loop dictionaries three ways: .keys(), .values(), and .items()
  • Recognize and navigate nested data (dicts in lists, lists in dicts, dicts in dicts)
  • Choose between list and tuple based on whether data should be mutable or immutable
  • Apply tuple unpacking to assign multiple variables in one line
  • Return multiple values from a function using a tuple
  • Recognize that strings are sequences too — sliceable, iterable, indexable like lists
  • Use the eight most common string methods: .lower(), .upper(), .strip(), .replace(), .split(), .join(), .find(), .startswith()
  • Build a complete CRUD app (Contact Vault) that combines list + dict + tuple + string in one program

Prerequisites

Units 1–4. Students must be fluent with: variables, all primitive data types, all operators, conditionals, both loops, basic lists with .append() and sorted(), functions with parameters & returns, scope, and the SDLC. Unit 5 introduces few new structural ideas — most of the unit is new methods on data types students already partially know.

What comes next

Unit 6 introduces file I/O and modules — students will take their Unit 5 data structures and persist them to disk. The Unit 6 capstone is "Persistent Contact Vault" — the same Vault from Unit 5, but now contacts survive program restarts via JSON files. The data structures from Unit 5 become the foundation for everything Units 6–10 build on top of.

Materials you'll need

  • Computers with web browser access (one per student, or pairs)
  • Knowledge Pillars CodeSkills Lab access
  • Projector or large screen — Unit 5's interactive widgets (the Path Explorer in L3 especially) work best in projection
  • Whiteboard with multiple colors — used heavily in Lesson 3 for nested-data diagrams (boxes inside boxes)
  • Optional: printed string-method quick-reference card (one per student) — tape to monitor for Lessons 5
  • Optional: a printed list/dict/tuple "decision tree" handout for Lesson 4 — helps students choose the right structure
🎯 Course alignment. Unit 5 is the home of Florida CTE standard 04.03 (sorting and filtering of data sets) and provides depth on 07.05 (variable types) by adding three new built-in data structures. The unit applies 05.06 (multiple algorithms) heavily — different ways to loop a dict, different ways to filter a list — and reinforces 02.02 (programming language components) since data structures ARE the components. See the Standards Crosswalk below for full detail.

⏱️ Pacing Guide

Unit 5 is designed for 8–10 class periods. Lessons 1, 2, and 3 are intentionally 50 minutes (data-structure depth takes time); Lesson 4 (tuples) is 45 minutes (lighter); Lesson 5 (Contact Vault capstone) is a 2-day project. Unit 5 is broader rather than deeper — many small new tools rather than one big concept.

Recommended pacing — 9-day plan

DayLessonFocusHomework
Day 1L1: Lists Level Up (pt 1)Indexing refresher. List methods: .append(), .insert(), .remove(), .pop(), .extend(), .index(), .count(), in. Lab 5.1A.Read L1 Section 3 (slicing)
Day 2L1: Lists Level Up (pt 2)Slicing. Iteration patterns (filter, map, accumulate). Lab 5.1B. Knowledge check.Read L2 Sections 1–2 (dicts intro)
Day 3L2: DictionariesLists vs dicts. Creating + reading. Update/add/delete. .get() safe lookups. Lab 5.2A.Read L3 Sections 1–2 (looping dicts)
Day 4L3: Looping Dicts & Nested (pt 1)Three loop methods. Common patterns. Lab 5.3A.Read L3 Sections 3–5 (nested data)
Day 5L3: Looping Dicts & Nested (pt 2)Nested data. Path Explorer. Looping nested. Lab 5.3B. Knowledge check.Read L4 Sections 1–2 (tuples intro)
Day 6L4: TuplesAnatomy. List vs tuple. Tuple unpacking. When to use tuples. Lab 5.4A. Knowledge check.Read L5 Sections 1–2 (strings)
Day 7L5: Strings (pt 1)Strings as sequences. The 8 string methods. f-strings. Lab 5.5A.Plan Contact Vault data shape on paper
Day 8L5: Contact Vault (pt 2)SDLC stages 1–2: Plan + Code. Students build the 5 functions.Continue building at home
Day 9L5: Contact Vault (pt 3)SDLC stages 3–5: Test + Fix + Maintain. Showcase. Submit.—

Compressed 8-day pacing

If you need to compress: combine Day 1 and Day 2 (cover all of Lesson 1 in one period). Most students who completed Unit 4 well can handle this — list methods feel familiar after the function-call practice. Recommended for groups who showed strong fluency in Unit 4's labs.

Extended 10-day pacing

If your class needs more time: split Lesson 3 into three days instead of two. Day 4 covers loop methods only. Day 5 covers nested data with whiteboard work. Day 6 has students draw their own nested-data diagrams. Drawing nested data is what locks the concept in — students who can SKETCH the structure can WRITE the code that navigates it.

⏱️ Where the time usually goes. Lesson 1 (lists) often runs fast — methods feel intuitive after Unit 4. Lesson 2 (dicts) is the unit's "click moment" — students need to see 2–3 different examples before the key/value mental model clicks. Lesson 3 (nested data) is the highest-friction lesson; lean into the Path Explorer widget. Lesson 4 (tuples) feels easy because tuples are mostly "lists with a different name" — but the WHEN to use tuples is the harder lesson. Lesson 5's Contact Vault always benefits from the full 2 days; the integration is what makes it stick.

Suggested grading weights for Unit 5

ComponentWeightNotes
Lesson Knowledge Checks (×4)15%3 questions each, completed in-platform
Lab Exercises (×8)30%Heavy on CodeSkills Lab — students PRACTICE all the methods
Contact Vault Final Project45%Capstone — 100-pt rubric in Lesson 5 plan
Class participation10%Whiteboard work, Path Explorer demos, peer code reviews

Note: Contact Vault is the second-heaviest capstone of the year (45%, matching Mad Libs 4.0). It integrates four data structures + the SDLC + clean code style. A student who does well on Contact Vault has genuinely mastered the year's first half.

🎓 Standards & Exam Crosswalk

This crosswalk shows exactly which Florida CTE standards and Coding Fundamentals exam objectives each lesson addresses. Use this for admin reviews, IEP documentation, or to prove alignment when adopting the curriculum. Unit 5's primary "new" standard is 04.03 (sorting/filtering data sets) — the unit applies it across all four data structures. The capstone (Contact Vault) is the unit's culminating performance task and addresses the broadest set of standards in the unit.

Florida CTE Standards — Course #9009200

Standards from the Florida Department of Education Coding Fundamentals curriculum framework that Unit 5 addresses:

StandardDescriptionLessons
01.01Use specialized computer coding software to solve problems.All (CodeSkills Lab)
01.02Demonstrate proficiency using specialized computer software (e.g., Python).All
02.02Explain the components of programming languages.L1, L2, L3, L4, L5 (data structures are core components)
04.03Demonstrate the sorting and filtering of data sets.L1, L2, L3, L5 — primary unit standard
05.06Recognize that more than one algorithm can solve a given problem.L1 (filter patterns), L3 (loop methods), L5
05.07Create a program that implements an algorithm to achieve a given goal.L5 (Contact Vault)
06.03Apply iterative debugging within the SDLC.L5 (Contact Vault testing)
07.01Describe the structure of a simple program; explain why sequencing is important.L5 (modular Vault)
07.05Explain the types and use of variables in programming.L1, L2, L3, L4 — full depth on four data types
07.07Troubleshoot and debug errors in code.L5 (data-shape bugs)

Coding Fundamentals Exam Objectives

Exam objectives that Unit 5 prepares students for. Data structures show up across multiple objectives — Unit 5 is the unit that fills out coverage breadth.

ObjTitleCoverage in Unit 5Lessons
1Core programming conceptsContinued — data structures are coreL1, L2, L3, L4, L5
2Analyze and predict code behaviorReinforced — students predict mutability, slicing, dict accessL1, L2, L4
4Write and debug simple programsHeavy — Contact Vault is a real working appL5
5Data manipulationFull coverage — primary objective for the unitL1, L2, L3, L5

Lesson-by-lesson alignment

LessonFlorida StandardsExam Objectives
L1: Lists Level Up01.01, 01.02, 02.02, 04.03, 07.051, 2, 5 (primary)
L2: Dictionaries01.01, 01.02, 02.02, 04.03, 07.051, 2, 5 (primary)
L3: Looping Dicts & Nested01.01, 01.02, 02.02, 04.03, 05.06, 07.051, 2, 5 (primary)
L4: Tuples01.01, 01.02, 02.02, 07.051, 2
L5: Strings & Contact Vault01.01, 01.02, 02.02, 04.03, 05.06, 05.07, 06.03, 07.01, 07.05, 07.071, 2, 4, 5 (primary)
📋 What's not in Unit 5. These standards are NOT addressed in Unit 5 and appear in later units: 03.x (file types) — Unit 6 · 07.02 (algorithms, deeper) — already covered in Unit 3 · 07.03 (loops, deeper) — already covered in Unit 2 · 07.04 (selection structures, deeper) — already covered in Units 1–2 · 07.06 (pseudocode/flowcharts) — already covered in Unit 3 · 07.08 (databases) — Unit 10. Note: students APPLY 07.02–07.04 throughout Unit 5 even though those standards are not its focus.

📖 Unit 5 Vocabulary Glossary

All 20 key terms students will encounter in Unit 5. The "Intro" column shows the lesson where each term first appears. Each lesson plan also includes its own focused vocabulary list. Most of Unit 5's vocabulary is concrete Python — methods and structures students will type and run rather than abstract ideas.

TermDefinitionExampleIntro
IndexingAccessing one item by its position. Lists are zero-indexed: first item is [0]. Negative indexes count from the end.names[0], names[-1]L1
SlicingGrabbing a sub-section using [start:stop:step]. Stop is exclusive. Negative values OK.names[1:3], text[::-1]L1
List MethodA function attached to a list, called with dot notation. Most modify the list in place.names.append("Sam")L1
MutabilityWhether a value can be changed after creation. Lists and dicts are mutable; strings and tuples are immutable.Lists: yes. Strings: no.L1 / L4
in operatorTests membership. Returns True/False. Works on lists, strings, dicts, tuples."a" in "cat" → TrueL1
Dictionary (dict)An unordered collection of key-value pairs. Curly braces. Keys are unique; values can be anything.{"name": "Alex", "age": 13}L2
KeyThe label that identifies a value in a dict. Usually a string. Must be unique within the dict."name" in {"name": "Alex"}L2
ValueThe data associated with a key. Can be ANY Python type — including another dict or list."Alex" in {"name": "Alex"}L2
Key-Value PairOne entry in a dict: a key and its associated value. Joined with a colon."age": 13L2
.get()Safe dict lookup. Returns the value if the key exists, or a default (None or your choice) if not. Doesn't crash.d.get("phone", "N/A")L2
.keys() / .values() / .items()Three ways to loop a dict. Items returns key-value pairs as tuples — most useful.for k, v in d.items():L3
Nested DataA data structure inside another. Dict of lists, list of dicts, dict of dicts. Common in real apps.List of contact dictsL3
TupleAn ORDERED, IMMUTABLE collection. Parentheses (or none, with commas). Use for fixed grouping.(40.7, -74.0)L4
ImmutabilityCannot be changed after creation. Tuples and strings are immutable. Operations create NEW values.Trying to t[0] = 5 crashesL4
Tuple UnpackingAssigning multiple variables from a tuple in one line. Used heavily for multi-return functions.x, y = (3, 5)L4
SequenceAn ordered collection that supports indexing, slicing, and iteration. Lists, tuples, AND strings are all sequences.All can be sliced with [1:3]L5
String MethodA function attached to a string. Returns a NEW string (strings are immutable)."Hi".lower() → "hi"L5
.split() / .join()The "list ↔ string" pair. .split turns a string into a list of pieces; .join turns a list back into a string."a,b".split(",") → ["a","b"]L5
.strip()Removes whitespace from both ends of a string. Critical for cleaning user input." hi ".strip() → "hi"L5
CRUDCreate, Read, Update, Delete. The four basic operations on data. Every database app — including the Contact Vault — implements CRUD.Add/list/edit/remove contactsL5
📖 Teaching tip. 20 terms is a lot — but most are method names students will use repeatedly. The five they MUST own by the end of unit: dict, key, value, .get(), .items(). Drill those weekly through the rest of the year. The list methods (.append, .remove, .pop, .extend) and string methods (.lower, .strip, .split) are best learned through repeated use in labs — not flash-card memorization. The concept students need is "different data structures have different superpowers."

📋 Lesson 1 · Lists Level Up

Lesson 1 · Lists Level Up

Lesson Plan

At-a-Glance

Objective
Students will use the seven essential list methods (.append, .insert, .remove, .pop, .extend, .index, .count) plus the in operator, slice lists with [start:stop:step] notation, and recognize the three iteration patterns: filter, map, and accumulate.
Time
50 minutes (often split across 2 days for slicing + iteration patterns)
Materials
Computer, CodeSkills Lab, projector, whiteboard
Vocabulary
Indexing, Slicing, List Method, Mutability, in operator
FL Standards
01.01, 01.02, 02.02, 04.03, 07.05
Exam Obj.
Objectives 1, 2, 5 (primary)

Lesson Flow (50 minutes)

🔥 Warm-Up (5 min)

  • Project: scores = [85, 72, 91, 58, 100]. Ask the class: "What if I want to add an 80? Remove the 58? Find the highest? Cut out just the middle three?" Take quick guesses.
  • Reveal: today is the day Python's lists become a Swiss Army knife. Each one of those tasks is one method or one slice away.

🎤 Direct Instruction (15 min)

  • Open Lesson 5.1 on the projector. Walk through Section 1 ("Quick Refresher: Indexing"). Drill: lists are zero-indexed. [0] is first; [-1] is last.
  • Walk through Section 2 ("The Essential List Methods"). Live-code each method with the same sample list. After each, ask: "Did this CHANGE the list, or RETURN something new?" Most modify in place — that's mutability.
    • .append(x) — add to end
    • .insert(i, x) — add at index i
    • .remove(x) — delete first occurrence of x
    • .pop() or .pop(i) — remove and RETURN last (or at index)
    • .extend(other) — add all items from another list
    • .index(x) — return position of first x
    • .count(x) — count occurrences of x
    • x in list — True/False membership test
  • Walk through Section 3 ("Slicing"). Drill: [start:stop] is half-open — stop is EXCLUSIVE. nums[1:3] grabs indices 1, 2 (not 3). Also: optional step — nums[::2] grabs every other.
  • Walk through Section 4 ("Iteration Patterns"). The three patterns:
    • Filter: build a results list of items that match a condition. passing = [s for s in scores if s >= 60] — but at this stage, use the explicit form: passing = []; for s in scores: if s >= 60: passing.append(s).
    • Map: transform each item. doubled = []; for n in nums: doubled.append(n * 2).
    • Accumulate: build up a single value. total = 0; for n in nums: total += n. (Unit 2 callback.)

🤝 Guided Practice (10 min)

  • On the whiteboard, write: numbers = [3, 1, 4, 1, 5, 9, 2, 6]. Walk through:
    • "What is numbers[3]?" (1)
    • "What is numbers[-2]?" (2)
    • "What is numbers[2:5]?" ([4, 1, 5])
    • "What is numbers.count(1)?" (2)
    • "What does numbers.pop() return AND leave?" (returns 6; leaves [3,1,4,1,5,9,2])
  • Have students predict each answer before revealing.

💻 Independent Lab (15 min)

  • Lab 5.1A — "Method Maze": students take a starter list and apply 8 method calls in sequence, predicting and verifying the result after each. Build the muscle memory.
  • Lab 5.1B — "Filter, Map, Accumulate": students implement all three patterns on the same list. Filter all words longer than 4 letters; Map each word to its uppercase; Accumulate the total length of all words.
  • Circulate. Common bugs: confusing .remove(x) (removes by VALUE) with .pop(i) (removes by INDEX); using .append(list) when they meant .extend(list) (creates a nested list, not a flat one).

🚪 Exit Ticket (5 min)

  • On paper: "Given data = [10, 20, 30, 40, 50], write the line of code that:"
    1. "Adds 60 to the end."
    2. "Returns the value at index 2."
    3. "Returns the slice containing 20 and 30."
  • Answers: data.append(60); data[2] (which is 30); data[1:3]. Common error: writing data[1:2] for #3 (forgets stop is exclusive).

⚠️ Watch For — Common Misconceptions

1. "Slicing's stop value is inclusive."
What you'll see: A student writes data[1:3] expecting it to include index 3.
How to address: Drill: stop is EXCLUSIVE. data[1:3] = indices 1 and 2 only. Memory hook: "stop AT index 3" means stop just BEFORE it. Same as range() from Unit 2 — range(5) gives 0,1,2,3,4. Same convention; same mental model.
2. ".append() vs .extend() confusion."
What you'll see: nums.append([4, 5, 6]) when they meant .extend. Result: [1, 2, 3, [4, 5, 6]] — a nested list, not a flat one.
How to address: Drill: .append(x) adds x as one item, even if x is a list. .extend(other) adds each item of other. The fix is one keyword. Show both side by side; the difference is dramatic.
3. ".remove() returns the removed item."
What you'll see: x = nums.remove(5). Then x is None — students surprised.
How to address: .remove(x) modifies in place and returns None. If you want the removed item, use .pop() or .pop(index) — those return the removed value. Echo of Unit 4's "None from print-only functions" pattern.
4. "Modifying a list while iterating it."
What you'll see: A student loops nums and calls nums.remove(x) inside. Items get skipped because the indices shift mid-loop. Silent bug.
How to address: Cardinal rule: don't modify a list you're iterating. Either iterate a COPY (for n in nums[:]:) or build a NEW list (filter pattern). The filter pattern is cleaner and Pythonic.

🎯 Differentiation

For early finishers
Challenge: implement filter, map, AND accumulate in a single function that takes a list of names and returns "the count of names that start with a vowel, all uppercased." Combines all three patterns. Stretch: research list comprehensions and rewrite Lab 5.1B with one-liners.
For struggling students
Stay on Lab 5.1A only. Skip slicing edge cases (negative indices, step values) for class time. The win: use .append, .remove, .pop, and in correctly. Slicing and iteration patterns can be revisited.

💬 Discussion Prompts

  • Why is the first index 0 instead of 1? (Historical: indices originally meant "offset from start." Position 0 means "no offset — the first item." The convention stuck across most languages. Some languages — Lua, R — start at 1, but they're the exceptions.)
  • Why does Python have so many list methods? (Each method represents a common operation. Programmers built lists, noticed they kept doing the same things, and added shortcuts. .append is just list[len(list):] = something — but .append reads better.)
  • If you could only have ONE list method, which would you keep? (Most people say .append — without it you can't grow a list. Some say in — without it, membership tests are loops. There's no "right" answer; the discussion exposes how students think about data.)

🌍 Real-World Connections

  • Shopping carts. Every "Add to Cart" button is .append. "Remove" is .remove. The cart count is len(). Modern e-commerce is built on list operations.
  • Music playlists. Adding songs, reordering, removing — all list methods. Spotify's "your queue" is literally a list with .append and .pop(0) (FIFO).
  • Photo albums. Phone gallery is a list of photos. Sorting by date = sorted(). Slicing to "last 30 days" = list slicing.
  • Spreadsheets. A column in a spreadsheet is a list. Formulas like SUM and COUNT are the accumulate pattern.

📖 Lesson-Specific Vocabulary

Indexing — Accessing one item by position. Zero-based. Negative indexes count from the end.
Slicing — Grabbing a sub-section with [start:stop:step]. Stop is EXCLUSIVE.
List Method — A function attached to a list. Most modify in place.
Mutability — Whether a value can be changed after creation. Lists are mutable.
in operator — Membership test. Returns True/False.
↑ Back to top

🗝️ Lesson 2 · Dictionaries

Lesson 2 · Dictionaries

Lesson Plan

At-a-Glance

Objective
Students will distinguish dictionaries from lists, create dictionaries with curly-brace syntax, read values by key with d[key], add/update/delete entries, and use .get() for safe lookups that don't crash on missing keys.
Time
50 minutes
Materials
Computer, CodeSkills Lab, projector, whiteboard
Vocabulary
Dictionary, Key, Value, Key-Value Pair, .get()
FL Standards
01.01, 01.02, 02.02, 04.03, 07.05
Exam Obj.
Objectives 1, 2, 5 (primary)
⚠️ The "click moment" of Unit 5. Dictionaries are the data structure students will use most for the rest of their career. Every API response, every config file, every database row — they're all dicts. Don't rush this lesson. Most students need 2–3 different examples before the key/value mental model clicks.

Lesson Flow (50 minutes)

🔥 Warm-Up (5 min)

  • Project: names = ["Alex", "Sam", "Riley"]. Then add: ages = [13, 14, 12]. Then ask: "What's Sam's age?"
  • Take answers. Walk through it: "We have to find Sam in names, get the index (1), then look up ages[1]." Annoying — and easy to break if the lists get out of sync.
  • Reveal: today we learn the data structure that solves this in one line. ages_by_name = {"Alex": 13, "Sam": 14, "Riley": 12}. ages_by_name["Sam"]. Done.

🎤 Direct Instruction (15 min)

  • Open Lesson 5.2 on the projector. Walk through Section 1 ("Lists vs Dictionaries"). On the whiteboard, draw a list as a row of boxes labeled 0, 1, 2... Draw a dict as a column of pairs (key → value). Visual difference = ordered-by-position vs labeled-by-key.
  • Walk through Section 2 ("Creating & Reading Dictionaries"). Live-code:
    • contact = {"name": "Alex", "phone": "555-1234"}
    • print(contact["name"]) → "Alex"
    • print(contact["age"]) → KeyError CRASH
  • The KeyError is the gateway to .get(). Show: print(contact.get("age", "unknown")) → "unknown". No crash. The professional way to look up.
  • Walk through Section 3 ("Update, Add & Delete"):
    • Update: contact["phone"] = "555-9999"
    • Add: contact["email"] = "alex@x.com" (same syntax as update — Python decides based on key existence)
    • Delete: del contact["phone"]
  • Walk through Section 4 ("Safe Lookups"). Drill .get() with two arguments: key and default value. The default returns when the key is missing.
  • Walk through Section 5 ("Why Dictionaries Are Everywhere"). Project examples: API JSON responses, config files, user profiles. Reveal: JSON is just a dict in text form. (Preview Unit 6.)

🤝 Guided Practice (10 min)

  • On the whiteboard, build a class roster dict together: keys are student names, values are scores. Add a few entries; update one; delete one; print the final state.
  • Ask: "What if I want all the names? All the scores? All the pairs?" Preview Lesson 3's .keys(), .values(), .items() — but don't deep-dive yet.

💻 Independent Lab (15 min)

  • Lab 5.2A — "Build a Profile": students create a dictionary representing themselves with at least 5 keys (name, age, favorite_color, hobbies as a list, hometown). Update one field. Delete one. Print the final dict.
  • Lab 5.2B — "Safe Lookup Practice": students take a profile dict and use .get() to print 5 fields, some of which exist and some don't. The non-existent ones use sensible defaults ("N/A" or "unknown").
  • Circulate. Common bugs: trying to use contact[0] (lists use indices, dicts use keys); putting numbers as keys without quotes when they meant strings ({1: "one"} creates a number-keyed dict, which is technically valid but usually unintended).

🚪 Exit Ticket (5 min)

  • On paper: "Given p = {"name": "Sam", "age": 14}, write what the following lines do:"
    1. p["age"] = 15
    2. p.get("phone", "N/A")
    3. del p["age"]
  • Answers: 1) updates age to 15. 2) returns "N/A" (phone key doesn't exist). 3) removes the age key entirely.

⚠️ Watch For — Common Misconceptions

1. "Dicts are accessed by index like lists."
What you'll see: contact[0] on a dict. Crashes with KeyError: 0.
How to address: Lists are accessed by POSITION; dicts are accessed by KEY. The whole point of a dict is that you LOOK UP by name, not by where it sits. Reinforce with the warm-up: that's exactly the problem dicts solve.
2. "Forget to quote string keys."
What you'll see: contact[name] instead of contact["name"]. Either crashes (NameError if no variable called name) or returns wrong value (if there IS such a variable).
How to address: Keys that ARE strings need quotes inside brackets. contact["name"] = look up the key spelled n-a-m-e. contact[name] = use the variable name as the key. Both are valid Python; the meanings are different.
3. ".get() always returns None."
What you'll see: Students don't pass a default and are surprised to get None back when keys are missing.
How to address: .get(key) returns None if missing. .get(key, default) returns default if missing. Show both. The two-argument form is what you usually want — "N/A" or 0 or "" as the default.
4. "Updating with [] only works on existing keys."
What you'll see: Students think they need a special "add" method and search for .add(). (There isn't one.)
How to address: The bracket assignment d[key] = value works for BOTH adding and updating. Python decides automatically based on whether the key exists. This is a feature — fewer methods to remember.
5. "Duplicate keys."
What you'll see: A student writes {"name": "Alex", "name": "Sam"} and is surprised the dict only has one entry.
How to address: Keys MUST be unique within a dict. The second assignment OVERWRITES the first. If you need multiple values per key, the value should be a list: {"names": ["Alex", "Sam"]}. Preview nested data (Lesson 3).

🎯 Differentiation

For early finishers
Challenge: build a "vending machine" dict where keys are item names and values are prices. Write a function buy(item, money) that uses .get() to handle "we don't sell that" gracefully. Stretch: research dict.setdefault() and explain how it differs from .get() in 2 sentences.
For struggling students
Skip Lab 5.2B. Stay on Lab 5.2A and focus on creating, reading with contact["name"], and updating. Skip .get() for class time — they'll see it again throughout Unit 5. The win: build a dict from scratch with 4+ keys and read values by their names.

💬 Discussion Prompts

  • You've been using dicts all year without knowing it. Where? (Web cookies. URL query strings. JSON in app responses. Even your character in a video game has stats stored in a dict-like structure.)
  • What's a real-world thing that's "key-based" rather than "position-based"? (A library card catalog. A phone book by name. Your school records by student ID. A locker by locker number. The world's full of dicts; we just don't call them that.)
  • Could a list and a dict store the same data? (Yes — in different shapes. A list of [name, age] pairs is the same data as {name: age}. The DICT is faster to look up by name. The LIST keeps order. Choose based on what you do with it most often.)

🌍 Real-World Connections

  • JSON. The format every app uses to talk to servers. JSON is literally a dict in text form. {"name": "Alex"} is valid JSON AND valid Python. Preview Unit 6.
  • Config files. Most apps have settings files that are dicts: theme, language, notifications. Same shape every time.
  • User profiles. Your Instagram/TikTok/Discord profile is a dict on a server: name, bio, posts (a list inside the dict — preview L3). When you edit settings, the app does profile["bio"] = "new bio".
  • Game state. Every player's character has a dict: HP, level, inventory (a list inside), equipped items (another dict).

📖 Lesson-Specific Vocabulary

Dictionary (dict) — An unordered collection of key-value pairs. Curly braces.
Key — The label that identifies a value. Usually a string. Must be unique within the dict.
Value — The data associated with a key. Can be any Python type.
Key-Value Pair — One entry in a dict. Joined with a colon.
.get(key, default) — Safe lookup. Returns value if key exists, default otherwise. Doesn't crash.
↑ Back to top

🪆 Lesson 3 · Looping Dicts & Nested Data

Lesson 3 · Looping Dicts & Nested Data

Lesson Plan

At-a-Glance

Objective
Students will use the three dict iteration methods (.keys(), .values(), .items()) and apply them to common patterns. Students will navigate nested data structures (lists of dicts, dicts containing lists) by chaining indexing and key lookups.
Time
50 minutes (typically split across 2 days)
Materials
Computer, CodeSkills Lab, projector, whiteboard with multiple colors for nested-structure diagrams
Vocabulary
.keys(), .values(), .items(), Nested Data
FL Standards
01.01, 01.02, 02.02, 04.03, 05.06, 07.05
Exam Obj.
Objectives 1, 2, 5 (primary)
⚠️ Highest-friction lesson of Unit 5. Nested data is where students hit their second "this is hard" moment of the year (the first was Unit 4 functions). The Path Explorer widget exists precisely to make navigation visible. Use it generously. The concept that locks it in: read nested access LEFT TO RIGHT — users[0]["hobbies"][2] means "users → first user → their hobbies → third hobby."

Lesson Flow (50 minutes — single-day version)

🔥 Warm-Up (5 min)

  • Project a dict: scores = {"Alex": 85, "Sam": 92, "Riley": 78}. Ask: "How do you print just the names? Just the scores? Both together?"
  • Most students try for x in scores — that gives keys (names). Walk through what they get. Reveal: today we learn 3 ways to loop a dict, and which one to use when.

🎤 Direct Instruction — Looping Dicts (12 min)

  • Open Lesson 5.3 on the projector. Walk through Section 1 ("Three Ways to Loop a Dictionary"):
    • for key in scores: — gives just keys (names)
    • for value in scores.values(): — gives just values (scores)
    • for key, value in scores.items(): — gives BOTH at once via tuple unpacking
  • The .items() form is the most useful — drill it. Live-code: for name, score in scores.items(): print(f"{name}: {score}").
  • Walk through Section 2 ("Patterns You'll Use Constantly"):
    • Find the max: loop .items() to find the highest-value key.
    • Filter: build a list of keys whose values match a condition.
    • Count by category: use a dict as a counter (counts[item] = counts.get(item, 0) + 1).

🎤 Direct Instruction — Nested Data (15 min)

  • Walk through Section 3 ("Nested Data — Structures Inside Structures"). On the whiteboard, draw nested structures with colored boxes inside boxes:
    • List of dicts: the most common shape. Used for "many records" — the Contact Vault uses this.
    • Dict of lists: grouped data. {"vegetables": ["carrot", "kale"], "fruits": ["apple"]}.
    • Dict of dicts: records keyed by id. {"alex": {"age": 13}, "sam": {"age": 14}}.
  • Walk through Section 4 ("Path Explorer"). Use the interactive widget. Project. Click through 5–6 example paths together. Build the read-left-to-right intuition.
  • Walk through Section 5 ("Looping Through Nested Data"). Live-code: looping a list of contact dicts to print each contact's name. The pattern is "outer loop, inner access."

💻 Independent Lab (13 min)

  • Lab 5.3A — "Loop the Dict": students take a class-roster dict and write three different loops — one printing names, one printing scores, one printing both. Then they identify the highest scorer with a max-finding loop.
  • Lab 5.3B — "Navigate the Nested": students get a list of student dicts (each with name, hobbies as a list, location as a tuple). Tasks: print each student's name; print each student's first hobby; find the student with the most hobbies.
  • Circulate. The biggest stumbling block: students try to access students["name"] when students is a LIST of dicts. They need students[0]["name"] first. Read left to right.

🚪 Exit Ticket (5 min)

  • On paper: "Given data = [{"name": "Alex", "scores": [85, 92]}, {"name": "Sam", "scores": [78, 88]}], write the expression that gets:"
    1. "Alex's name."
    2. "Sam's first score."
    3. "The number of students."
  • Answers: 1) data[0]["name"]. 2) data[1]["scores"][0]. 3) len(data). The middle one is the most-confused — it requires three left-to-right steps.

⚠️ Watch For — Common Misconceptions

1. "for x in dict gives values."
What you'll see: for s in scores: print(s) — student expects scores; gets names. Confusion.
How to address: Default dict iteration gives KEYS, not values. To get values, use .values(). To get both, use .items(). The default behavior is the surprising one — drill it.
2. "Skip .items() in favor of two separate loops."
What you'll see: A student writes a loop for keys, then ANOTHER loop for values, when they could've gotten both in one with .items().
How to address: Show .items() first. The tuple unpacking for k, v in d.items(): is Pythonic and clean. Reduces code in half. Once students see it work, they prefer it.
3. "Confusing list vs dict access in nested data."
What you'll see: students["name"] when students is a list. Or contact[0] when contact is a dict. Off by one level.
How to address: Ask: "What is students right now? A list or a dict?" If list → use [index]. If dict → use ["key"]. Read each step left to right; ask the question at each level. Use the Path Explorer widget to visualize.
4. "Mutating a dict while looping it."
What you'll see: Looping scores.items() and calling del scores[key] inside. Crashes with RuntimeError: dictionary changed size during iteration.
How to address: Same rule as Lesson 1: don't modify a structure you're iterating. Iterate a COPY of the keys (for k in list(scores.keys()):) or build a NEW dict via filter pattern.
5. "Dict of lists vs list of dicts."
What you'll see: Students conflate the two shapes. They try to do data["alex"] on a list of dicts.
How to address: Whiteboard the two shapes side by side. List of dicts: [ {"name": "Alex"}, {"name": "Sam"} ] — outermost is a LIST, accessed by index. Dict of dicts: { "alex": {"age": 13}, "sam": {"age": 14} } — outermost is a DICT, accessed by key. The Contact Vault uses the LIST OF DICTS shape.

🎯 Differentiation

For early finishers
Challenge: given a list of dicts (students with hobbies), write a function that returns a dict mapping each hobby to the list of students who have it. Inverts the data shape — common real-world transformation. Stretch: research dict comprehensions and rewrite the inversion in one line.
For struggling students
Skip nested data for class time. Stay on Lab 5.3A only — looping a flat dict three ways. The win: for k, v in d.items() works correctly. Nested data can be revisited the next day with extra Path Explorer practice.

💬 Discussion Prompts

  • When would you use a list of dicts vs a dict of dicts? (List of dicts: when ORDER matters or the records don't have a unique id (just append in arrival order). Dict of dicts: when LOOKUP by id is the most common operation. The Contact Vault uses list of dicts because contacts have NO unique id; we look up by name with substring matching.)
  • JSON files are usually dicts of dicts of lists of dicts... why? (Because that's the shape of most real data. A user has fields (dict). One field is "posts" — a list. Each post has fields — a dict. Each post has comments — another list. Real-world data nests naturally; that's why dicts and lists nest naturally too.)
  • What's the difference between a dict and a database? (Scale and persistence. A dict lives in memory and disappears when the program ends. A database lives on disk and persists. Conceptually, a database table is "a list of dicts" — same shape, different storage. Preview Unit 10.)

🌍 Real-World Connections

  • API responses. When your weather app calls a server, the response is a nested dict: {"weather": {"temp": 72, "conditions": [{"description": "sunny"}]}}. Reading it requires the exact same left-to-right navigation skill students learned today.
  • Game saves. A saved game is a nested dict: player info (dict), inventory (list of items, each a dict), world state (dict of dicts). Loading a save is just parsing JSON into Python data structures.
  • Social media feeds. Your Instagram feed is a list of posts. Each post is a dict. Each post has a list of comments. Each comment is a dict. List → dict → list → dict.
  • Spreadsheets in code. When a Python program reads a CSV, the natural representation is a list of dicts — one row per dict, column names as keys.

📖 Lesson-Specific Vocabulary

.keys() — Returns just the keys of a dict. Use when you only need names.
.values() — Returns just the values of a dict. Use when you only need data.
.items() — Returns key-value pairs as tuples. Use when you need BOTH.
Nested Data — A data structure inside another. Most common: list of dicts.
↑ Back to top

🔒 Lesson 4 · Tuples

Lesson 4 · Tuples

Lesson Plan

At-a-Glance

Objective
Students will create tuples, distinguish them from lists (mutability), apply tuple unpacking to assign multiple variables in one line, return multiple values from a function via tuples, and choose between list and tuple based on the data's nature.
Time
45 minutes
Materials
Computer, CodeSkills Lab, projector, whiteboard
Vocabulary
Tuple, Immutability, Tuple Unpacking
FL Standards
01.01, 01.02, 02.02, 07.05
Exam Obj.
Objectives 1, 2

Lesson Flow (45 minutes)

🔥 Warm-Up (5 min)

  • Project: location = [40.7, -74.0] # latitude, longitude. Ask: "What if a programmer accidentally writes location[0] = "hello"?" Reveal: the location is now broken. Lists let you change anything.
  • Reveal: today we meet Python's "lock" — a structure that REFUSES to be changed once created. Useful for fixed groupings like coordinates, RGB colors, dates.

🎤 Direct Instruction (12 min)

  • Open Lesson 5.4 on the projector. Walk through Section 1 ("Anatomy of a Tuple"). Live-code:
    • point = (3, 5) — tuple with parens
    • point = 3, 5 — tuple without parens (commas make a tuple)
    • point[0] → 3 (indexing works)
    • point[0] = 10 → TypeError CRASH (immutable)
  • Walk through Section 2 ("List vs Tuple — Same, Same, but Different"). Drill the differences:
    • Lists: mutable, square brackets, methods like .append(). Use for collections that grow/shrink.
    • Tuples: immutable, parentheses, no append, faster to create. Use for fixed groupings.
  • Walk through Section 3 ("Tuple Unpacking — A Genuine Superpower"). Live-code:
    • x, y = (3, 5) — assigns x=3, y=5 in one line
    • name, age = "Alex", 13 — same idea, no parens needed
    • def min_max(nums): return min(nums), max(nums) then lo, hi = min_max([1, 5, 3]) — multi-return functions
  • Walk through Section 4 ("When to Reach for a Tuple"). The decision: if the data describes ONE thing with multiple parts that won't change (coordinates, RGB color, date, person's full name + age), use a tuple. If you'll add/remove/change items, use a list.

🤝 Guided Practice (8 min)

  • On the whiteboard, present 6 scenarios. For each, students vote: list or tuple?
    • "User's shopping cart" → list (changes constantly)
    • "GPS coordinate (lat, lon)" → tuple (fixed)
    • "Player's high scores history" → list (grows)
    • "RGB color (r, g, b)" → tuple (fixed 3 components)
    • "To-do items" → list (add/remove)
    • "Day-month-year of an event" → tuple (fixed)
  • Discuss any vote where the class disagrees.

💻 Independent Lab (15 min)

  • Lab 5.4A — "Tuples in Action": students write a function get_min_max(numbers) that returns BOTH the min and max as a tuple. Caller unpacks: lo, hi = get_min_max([1,5,3]). Tests: positive list, negative list, mixed.
  • Lab 5.4B — "Choose the Structure": students get 5 data scenarios and write the correct Python literal — list or tuple — for each. Justification in a comment.
  • Circulate. Common bug: trying to use a list method like .append on a tuple. Crashes with AttributeError. The fix is to convert to a list first if needed: lst = list(my_tuple).

🚪 Exit Ticket (5 min)

  • On paper:
    1. "Will the line t = (1, 2, 3); t[0] = 99 work? Why or why not?"
    2. "Write a tuple representing your home as (city, state)."
  • Answers: 1) Crashes — tuples are immutable. t[0] = 99 isn't allowed. 2) Anything like ("Savannah", "GA") works.

⚠️ Watch For — Common Misconceptions

1. "Tuples need parentheses to exist."
What you'll see: A student is surprised that x, y = 3, 5 works without parens.
How to address: Tuples are made by COMMAS, not parens. Parens are optional but improve readability. 3, 5 is a tuple. (3, 5) is the same tuple. Use parens for clarity, especially in function returns.
2. "Single-item tuples don't exist."
What you'll see: t = (5). Student thinks they made a 1-item tuple. They didn't — that's just 5 in parens.
How to address: A single-item tuple needs a trailing comma: t = (5,). The comma is the tuple-maker. Annoying syntax wart but unavoidable.
3. "Immutability means you can't reassign the variable."
What you'll see: Confusion when t = (1, 2) followed by t = (3, 4) works fine.
How to address: Immutability means the TUPLE can't change. The VARIABLE pointing to it can. t = (3, 4) doesn't modify the original tuple — it creates a NEW tuple and re-points t at it. The old tuple is gone (garbage collected).
4. "Tuples are 'better' than lists because they're faster."
What you'll see: A student tries to use tuples for everything because they read tuples are "faster."
How to address: Tuples ARE slightly faster to create, but the difference is negligible for normal use. Choose based on MUTABILITY needs, not speed. If the data won't change, tuple. If it will, list. Speed is a tiebreaker, not a primary concern.

🎯 Differentiation

For early finishers
Challenge: write a function describe(point) that takes a tuple (x, y) and returns a tuple (distance_from_origin, quadrant). Use unpacking on input AND return. Stretch: research why dictionaries can use tuples as keys but not lists — and explain why in 2 sentences (hint: hashability).
For struggling students
Skip the multi-return function for class time. Focus on: create a tuple, index into it, try to modify it (see the crash), unpack it into two variables. The win: a tuple is "a list that won't let you change it."

💬 Discussion Prompts

  • If lists can do everything tuples can, why does Python have tuples? (Three reasons: SAFETY (immutability prevents accidental modification), SPEED (slight performance edge), and SIGNALING (a tuple TELLS the reader "this group is fixed"). The third reason is most important — code is communication.)
  • Where in math do you already use tuples without realizing? (Coordinates! (x, y) is a 2-tuple. (x, y, z) is a 3-tuple. RGB color is a 3-tuple. Vectors are tuples. The math notation IS the Python notation.)
  • If you wanted to store the corners of a square, list of tuples or list of lists? (List of tuples — each corner is a fixed (x, y) pair, but you have many corners that you might iterate. Outer = many = list. Inner = fixed = tuple.)

🌍 Real-World Connections

  • GPS coordinates. Every map app uses (latitude, longitude) tuples. (40.7, -74.0) = New York City. The pair is meaningless if you split them.
  • RGB colors. Every pixel on every screen is a 3-tuple (red, green, blue). (255, 0, 0) = red. Photoshop, web design, game graphics — all built on color tuples.
  • Database rows. A row in a database is conceptually a tuple — fixed shape, ordered fields. SQL even calls them "tuples" in some textbooks.
  • Function returns. Many library functions return tuples for multi-value results. divmod(7, 3) returns (2, 1) — quotient and remainder. Tuple unpacking makes this elegant.

📖 Lesson-Specific Vocabulary

Tuple — An ordered, immutable collection. Parentheses optional; commas required.
Immutability — Cannot be changed after creation. Operations create NEW values.
Tuple Unpacking — Assigning multiple variables from a tuple in one line. x, y = point.
↑ Back to top

📇 Lesson 5 · Strings & Contact Vault Capstone

Lesson 5 · Strings & Contact Vault

Project Plan

At-a-Glance

Objective
Students will recognize that strings are sequences (sliceable, iterable, indexable), use the eight most common string methods (.lower, .upper, .strip, .replace, .split, .join, .find, .startswith), and integrate all four data structures into the Contact Vault — a working contact-management app with at least 5 modular functions.
Time
Two class periods (60–90 minutes total)
Materials
Computer, CodeSkills Lab, projector, paper for SDLC plan stage, optional printed string-method reference card
Vocabulary
Sequence, String Method, .split(), .join(), .strip(), CRUD
FL Standards
01.01, 01.02, 02.02, 04.03, 05.06, 05.07, 06.03, 07.01, 07.05, 07.07
Exam Obj.
Objectives 1, 2, 4, 5 (primary)
⚠️ The unit's culminating project. Contact Vault integrates EVERY structure from Unit 5 (list + dict + tuple + string) plus everything from Unit 4 (functions, return values, modular code, SDLC). It's the second-heaviest capstone of the year (matching Mad Libs 4.0). Don't compress. Day 1 covers strings + Plan + Code stages; Day 2 covers Test + Fix + Maintain + Showcase. The 2-day pacing is non-negotiable for most classes.

Project Flow (90 minutes across 2 days)

📅 Day 1 — Strings + Plan + Code (45 min)

  • Warm-up (5 min): Project a messy user input: " Alex Garcia\n". Ask: "How do we clean this?" Take guesses. Reveal: today's first half is the toolkit for cleaning ANY string.
  • Direct Instruction — Strings (15 min): Walk through Lesson 5.5 Sections 1–3. Drill the 8 string methods:
    • .lower() / .upper() — case conversion
    • .strip() — remove leading/trailing whitespace (CRITICAL for input cleanup)
    • .replace(old, new) — substitute substrings
    • .split(sep) — turn a string into a list of pieces
    • "sep".join(list) — turn a list back into a string
    • .find(sub) — return position of substring (or -1 if not found)
    • .startswith(prefix) — True/False prefix check
  • Key insight: strings are immutable. Methods return NEW strings — they don't modify the original. Always assign: name = name.strip().
  • Capstone introduction (5 min): Project the Contact Vault data shape:
    vault = [
      {"name": "Alex Garcia",
       "phone": "5551234567",
       "email": "alex@x.com",
       "location": ("Savannah", "GA")},  # tuple inside dict
      ...
    ]
  • List of dicts. Each dict has 4 keys. The location value is a TUPLE (immutable — coordinates rarely change). The whole shape combines all four Unit 5 structures.
  • Plan stage (5 min): Distribute paper. Students write a 5-line plan: "I will build 5 functions: add_contact(), list_contacts(), search_contacts(query), remove_contact(name), main()." This is the Stage 1 deliverable.
  • Code stage (15 min): Students copy the starter scaffold from the lesson into CodeSkills Lab and start building the 5 functions. They'll finish at home or on Day 2.

📅 Day 2 — Test + Fix + Maintain + Showcase (45 min)

  • Test stage (10 min): Students apply edge-case testing — empty inputs, all-uppercase searches, non-existent contacts, duplicate names. They write a "test cases worksheet" at the bottom of their file documenting what they tried.
  • Fix stage (15 min): Apply the 4-step debugging strategy from Unit 4. Students pair up — they test EACH OTHER's vaults to surface bugs. The peer-test step is critical; students miss things in their own code.
  • Maintain stage (10 min): Polish — header comment block, docstrings on each function, version notes at the bottom, file saved as contact_vault.py. The polish is what separates a B project from an A project.
  • Showcase & Submit (10 min): Pick 3–5 volunteers to demo. Project both the running app AND the code. The class sees that the same problem has multiple valid solutions — different function signatures, different display formats, different search patterns.

⚠️ Watch For — Common Project Pitfalls

1. "String methods don't seem to work."
What you'll see: name.strip() on a line by itself. Then print(name) still shows leading whitespace. Confusion.
How to address: Strings are immutable. .strip() returns a NEW string; doesn't modify the original. Must reassign: name = name.strip(). The single most common bug in string handling. Echo of Unit 4's "None from print-only functions."
2. "Search is case-sensitive."
What you'll see: Searching "alex" doesn't find "Alex Garcia". The rubric explicitly requires case-insensitive search.
How to address: Lowercase BOTH sides before comparing: query.lower() in name.lower(). Drill this pattern. It's universal — every search box in every app does this.
3. "contact[0] instead of contact["name"]."
What you'll see: Lesson 3 carryover. Student tries to access dict by index.
How to address: Vault is a list of dicts. vault[0] = first contact (a dict). vault[0]["name"] = first contact's name. Read left to right. The Path Explorer training from L3 applies directly.
4. "Trying to mutate a tuple location."
What you'll see: A student tries to "update" a location with contact["location"][0] = "Atlanta". Crashes — tuples are immutable.
How to address: To change a location, replace the WHOLE tuple: contact["location"] = ("Atlanta", "GA"). Echo of Lesson 4. The whole point of using a tuple here is that addresses don't usually change in place — they replace.
5. "Forgot to .strip() input."
What you'll see: A user types "Alex " (trailing space) and the search for "Alex" doesn't find them. Silent bug.
How to address: Every input() call should be followed by .strip(). name = input("Name: ").strip(). The rubric explicitly requires this — 15 of 100 pts is "String Cleanup."
6. "Mutating the vault while iterating."
What you'll see: remove_contact loops the vault and calls vault.remove(c). Items get skipped or crashes.
How to address: Find the index first, then remove: for i, c in enumerate(vault): if c["name"].lower() == name.lower(): del vault[i]; return True. OR build a new vault via filter pattern. Don't mutate while iterating.

🎯 Differentiation

For students who finish early
Direct them to stretch goals from the lesson: sort the vault alphabetically (vault.sort(key=lambda c: c["name"].lower())), filter by state, pretty phone formatting via slicing, duplicate detection, CSV export string. Each adds +5 pts (max +20).
For struggling students
It's OK if their vault has 3 functions instead of 5 (skip remove_contact and combine list+search). They still demonstrate the data shape and CRUD basics. The win: a working app that adds, lists, and searches — even minimally — is genuine integration of Unit 5 structures.

💬 Discussion Prompts

  • Why is the location a TUPLE inside a DICT? (City + state describes ONE thing — a place — and rarely changes piece by piece. Tuple says "this is fixed." If you need to change it, replace the whole tuple.)
  • Could we have used a dict-of-dicts instead of a list-of-dicts? (Yes — keys could be names. But: names aren't unique enough (two "Alex"es). And we lose insertion order. The list-of-dicts shape is what real CRMs use because contacts have NO unique business id and order can matter for "recently added".)
  • The Contact Vault is the same data shape as a CRM (Salesforce, HubSpot). Why don't we just USE Salesforce? (For learning! Building it ourselves teaches what's happening underneath. Once you've built one, you understand how every CRM works internally.)

🌍 Real-World Connections

  • Every CRM in existence. Salesforce, HubSpot, Pipedrive — all built on list-of-dicts shapes (in their database, JSON in transit). The Contact Vault is a CRM with the persistence stripped out. Add Unit 6's file I/O and it becomes a real, persistent CRM.
  • Address books. Your phone's contacts app uses this exact shape internally. Add a contact, search by name, edit, delete — the SAME four functions you just built.
  • CRUD is universal. Every database app implements Create, Read, Update, Delete. The names change (sometimes "list/get" instead of "read"), but the shape is identical. Once you've built CRUD once, you've understood the basic structure of every business app.
  • JSON in transit. When your phone's contact app syncs with the cloud, the data is shipped as JSON — which is exactly the dict-and-list nesting you wrote today.

📋 Contact Vault Project Rubric (100 points)

The rubric matches the one in the student lesson exactly. Share with students at the start of Day 1.

CategoryWhat to look forPts
Data ShapeList of dicts; each dict uses name, phone, email, location; location is a TUPLE.15
Modular FunctionsAt least 5 well-named functions, each doing one job. main() wires them.20
String CleanupInputs cleaned with .strip(), .lower(), .replace() as appropriate. Search is case-insensitive.15
Search & FilterSearch uses substring matching (in) on lowercased names. Returns a list of matches.15
Clean Code Stylesnake_case names, 4-space indent, spaces around operators, blank lines between functions, docstrings.10
SDLC DocumentationPlan comments at top, test case results documented, version notes at bottom.10
Works CorrectlyAll 8 test cases from Stage 3 pass. No crashes on empty/missing data.15
TOTAL100

🎁 Stretch Goals (extra credit)

  • Sort the vault alphabetically with vault.sort(key=lambda c: c["name"].lower()): +5 pts
  • Filter by state (contacts_in_state(state) using location[1]): +5 pts
  • Pretty phone format on display via slicing: +5 pts
  • Duplicate detection on add: +5 pts
  • CSV export to a string using ", ".join([...]): +5 pts

Maximum stretch credit: +20 points. Document each stretch in version notes at the bottom of the file.

💡 Showcase tip. The Day 2 showcase is the unit's emotional payoff. Students see that they have built a real working app — the same shape that powers every CRM and address book on the planet. Project both the live demo AND the code briefly. Different students will have made different choices; show the class that the same problem has multiple valid solutions. This is standard 05.06 (multiple algorithms) made visible.

📖 Lesson-Specific Vocabulary

Sequence — An ordered collection that supports indexing, slicing, iteration. Lists, tuples, AND strings are all sequences.
String Method — A function attached to a string. Returns a NEW string (strings are immutable).
.split() / .join() — The list↔string pair. .split turns a string into a list; .join turns a list into a string.
.strip() — Removes whitespace from both ends. Use after every input().
CRUD — Create, Read, Update, Delete. The four basic operations on any data store.
↑ Back to top

🛠️ Appendix · Common Python Errors in Unit 5

This appendix lists the most common Python error messages students will see in Unit 5. Data structures introduce a new family of errors — KeyError on missing dict keys, IndexError on out-of-range list access, TypeError on tuple mutation, AttributeError on string methods used wrong. Apply Unit 4's 4-step strategy: Reproduce → Read → Hypothesize → Fix & Verify, ONE change at a time.

ERRORKeyError: 'name'

What it usually means: Tried to access a dict key that doesn't exist. The bracket form d["name"] CRASHES on missing keys.

How to fix: Use d.get("name", default) for safe lookups. Returns the default value (None or your choice) instead of crashing. The professional way to access dict values when you're not 100% sure the key exists.

ERRORIndexError: list index out of range

What it usually means: Tried to access a list index that doesn't exist. nums[5] on a 3-item list crashes.

How to fix: Check len(nums) first or use a try/except (Unit 6). Most often the bug is off-by-one in a loop. Trace by hand.

ERRORTypeError: 'tuple' object does not support item assignment

What it usually means: Tried to mutate a tuple. t[0] = 5. Tuples are immutable.

How to fix: Either replace the WHOLE tuple (t = (5, t[1])) or use a list instead. If you need to change items, you wanted a list.

ERRORAttributeError: 'list' object has no attribute 'lower'

What it usually means: Called a string method on a list (or other non-string). names.lower() when names is a list.

How to fix: Apply the method to each ITEM. [n.lower() for n in names] or a regular loop. Or if the variable should be a single string, check why it became a list.

ERRORRuntimeError: dictionary changed size during iteration

What it usually means: Modified a dict (added or deleted keys) inside a loop that was iterating it. Python catches this and crashes.

How to fix: Iterate over a COPY of the keys: for k in list(d.keys()):. Or build a new dict via filter pattern. Same rule as lists: don't mutate while iterating.

SILENT(string method had "no effect")

What it usually means: Called a method that returns a new string but didn't capture the result. name.strip() on its own line — the cleaned string is computed but immediately discarded.

How to fix: Reassign: name = name.strip(). The single most common bug in Unit 5 string handling. Strings are immutable; methods always RETURN new strings.

SILENT(.append creates a nested list)

What it usually means: Used .append([4, 5]) when you meant .extend([4, 5]). Result: [1, 2, 3, [4, 5]] instead of [1, 2, 3, 4, 5].

How to fix: Use .extend() when adding multiple items from another list. Use .append() when adding ONE item (which may itself be a list, if you want it nested).

SILENT(search returns wrong results — case mismatch)

What it usually means: Search for "alex" doesn't find "Alex Garcia" because comparison is case-sensitive.

How to fix: Lowercase BOTH sides before comparing: query.lower() in name.lower(). The Contact Vault rubric explicitly requires this.

CARRYOVERCarryover errors from Units 1–4

Watch list — these still happen in Unit 5 capstones:

  • SyntaxError: expected ':' — missing colon after def, if, for, or while.
  • TypeError: '>' not supported between instances of 'str' and 'int' — missed an int() wrap on input.
  • Functions returning None when expected a value — print instead of return. Echo of Unit 4 Lesson 3.
  • Indentation errors when functions and loops nest deeply — three or four levels in the Contact Vault is normal.
  • Variable scope issues: trying to read a function-local variable from outside the function. Pass through parameters and returns instead.
🛟 Data structure debugging adds one diagnostic question. Before applying the 4-step strategy, ask: "What SHAPE is my data right now?" Print it. Is it a list or a dict? Is it nested? What level am I trying to access? Most Unit 5 bugs are SHAPE bugs — the student is one indexing/key step off. Once the shape is clear, the fix is usually one character (a [ or a ").
📘 Companion document. A Unit 5 Answer Key with Knowledge Check answers and lab solutions can be authored separately on request. The Teacher's Guide + Answer Key are designed to be used together.

— End of Unit 5 Teacher's Guide —

↑ Back to top