Unit 5 – Teachers Guide
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.
👋 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,AttributeErroron 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
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 theinoperator - 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
⏱️ 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
| Day | Lesson | Focus | Homework |
|---|---|---|---|
| Day 1 | L1: 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 2 | L1: Lists Level Up (pt 2) | Slicing. Iteration patterns (filter, map, accumulate). Lab 5.1B. Knowledge check. | Read L2 Sections 1–2 (dicts intro) |
| Day 3 | L2: Dictionaries | Lists vs dicts. Creating + reading. Update/add/delete. .get() safe lookups. Lab 5.2A. | Read L3 Sections 1–2 (looping dicts) |
| Day 4 | L3: Looping Dicts & Nested (pt 1) | Three loop methods. Common patterns. Lab 5.3A. | Read L3 Sections 3–5 (nested data) |
| Day 5 | L3: Looping Dicts & Nested (pt 2) | Nested data. Path Explorer. Looping nested. Lab 5.3B. Knowledge check. | Read L4 Sections 1–2 (tuples intro) |
| Day 6 | L4: Tuples | Anatomy. List vs tuple. Tuple unpacking. When to use tuples. Lab 5.4A. Knowledge check. | Read L5 Sections 1–2 (strings) |
| Day 7 | L5: Strings (pt 1) | Strings as sequences. The 8 string methods. f-strings. Lab 5.5A. | Plan Contact Vault data shape on paper |
| Day 8 | L5: Contact Vault (pt 2) | SDLC stages 1–2: Plan + Code. Students build the 5 functions. | Continue building at home |
| Day 9 | L5: 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.
Suggested grading weights for Unit 5
| Component | Weight | Notes |
|---|---|---|
| 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 Project | 45% | Capstone — 100-pt rubric in Lesson 5 plan |
| Class participation | 10% | 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:
| Standard | Description | Lessons |
|---|---|---|
| 01.01 | Use specialized computer coding software to solve problems. | All (CodeSkills Lab) |
| 01.02 | Demonstrate proficiency using specialized computer software (e.g., Python). | All |
| 02.02 | Explain the components of programming languages. | L1, L2, L3, L4, L5 (data structures are core components) |
| 04.03 | Demonstrate the sorting and filtering of data sets. | L1, L2, L3, L5 — primary unit standard |
| 05.06 | Recognize that more than one algorithm can solve a given problem. | L1 (filter patterns), L3 (loop methods), L5 |
| 05.07 | Create a program that implements an algorithm to achieve a given goal. | L5 (Contact Vault) |
| 06.03 | Apply iterative debugging within the SDLC. | L5 (Contact Vault testing) |
| 07.01 | Describe the structure of a simple program; explain why sequencing is important. | L5 (modular Vault) |
| 07.05 | Explain the types and use of variables in programming. | L1, L2, L3, L4 — full depth on four data types |
| 07.07 | Troubleshoot 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.
| Obj | Title | Coverage in Unit 5 | Lessons |
|---|---|---|---|
| 1 | Core programming concepts | Continued — data structures are core | L1, L2, L3, L4, L5 |
| 2 | Analyze and predict code behavior | Reinforced — students predict mutability, slicing, dict access | L1, L2, L4 |
| 4 | Write and debug simple programs | Heavy — Contact Vault is a real working app | L5 |
| 5 | Data manipulation | Full coverage — primary objective for the unit | L1, L2, L3, L5 |
Lesson-by-lesson alignment
| Lesson | Florida Standards | Exam Objectives |
|---|---|---|
| L1: Lists Level Up | 01.01, 01.02, 02.02, 04.03, 07.05 | 1, 2, 5 (primary) |
| L2: Dictionaries | 01.01, 01.02, 02.02, 04.03, 07.05 | 1, 2, 5 (primary) |
| L3: Looping Dicts & Nested | 01.01, 01.02, 02.02, 04.03, 05.06, 07.05 | 1, 2, 5 (primary) |
| L4: Tuples | 01.01, 01.02, 02.02, 07.05 | 1, 2 |
| L5: Strings & Contact Vault | 01.01, 01.02, 02.02, 04.03, 05.06, 05.07, 06.03, 07.01, 07.05, 07.07 | 1, 2, 4, 5 (primary) |
📖 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.
| Term | Definition | Example | Intro |
|---|---|---|---|
| Indexing | Accessing one item by its position. Lists are zero-indexed: first item is [0]. Negative indexes count from the end. | names[0], names[-1] | L1 |
| Slicing | Grabbing a sub-section using [start:stop:step]. Stop is exclusive. Negative values OK. | names[1:3], text[::-1] | L1 |
| List Method | A function attached to a list, called with dot notation. Most modify the list in place. | names.append("Sam") | L1 |
| Mutability | Whether a value can be changed after creation. Lists and dicts are mutable; strings and tuples are immutable. | Lists: yes. Strings: no. | L1 / L4 |
| in operator | Tests membership. Returns True/False. Works on lists, strings, dicts, tuples. | "a" in "cat" → True | L1 |
| Dictionary (dict) | An unordered collection of key-value pairs. Curly braces. Keys are unique; values can be anything. | {"name": "Alex", "age": 13} | L2 |
| Key | The label that identifies a value in a dict. Usually a string. Must be unique within the dict. | "name" in {"name": "Alex"} | L2 |
| Value | The data associated with a key. Can be ANY Python type — including another dict or list. | "Alex" in {"name": "Alex"} | L2 |
| Key-Value Pair | One entry in a dict: a key and its associated value. Joined with a colon. | "age": 13 | L2 |
| .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 Data | A data structure inside another. Dict of lists, list of dicts, dict of dicts. Common in real apps. | List of contact dicts | L3 |
| Tuple | An ORDERED, IMMUTABLE collection. Parentheses (or none, with commas). Use for fixed grouping. | (40.7, -74.0) | L4 |
| Immutability | Cannot be changed after creation. Tuples and strings are immutable. Operations create NEW values. | Trying to t[0] = 5 crashes | L4 |
| Tuple Unpacking | Assigning multiple variables from a tuple in one line. Used heavily for multi-return functions. | x, y = (3, 5) | L4 |
| Sequence | An ordered collection that supports indexing, slicing, and iteration. Lists, tuples, AND strings are all sequences. | All can be sliced with [1:3] | L5 |
| String Method | A 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 |
| CRUD | Create, Read, Update, Delete. The four basic operations on data. Every database app — including the Contact Vault — implements CRUD. | Add/list/edit/remove contacts | L5 |
.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 PlanAt-a-Glance
.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.in operatorLesson 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 indexi.remove(x)— delete first occurrence ofx.pop()or.pop(i)— remove and RETURN last (or at index).extend(other)— add all items from another list.index(x)— return position of firstx.count(x)— count occurrences ofxx 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: optionalstep—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.)
- Filter: build a results list of items that match a condition.
🤝 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])
- "What is
- 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:"- "Adds 60 to the end."
- "Returns the value at index 2."
- "Returns the slice containing 20 and 30."
- Answers:
data.append(60);data[2](which is 30);data[1:3]. Common error: writingdata[1:2]for #3 (forgets stop is exclusive).
⚠️ Watch For — Common Misconceptions
data[1:3] expecting it to include index 3.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.nums.append([4, 5, 6]) when they meant .extend. Result: [1, 2, 3, [4, 5, 6]] — a nested list, not a flat one..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.x = nums.remove(5). Then x is None — students surprised..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.nums and calls nums.remove(x) inside. Items get skipped because the indices shift mid-loop. Silent bug.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.
.appendis justlist[len(list):]= something — but.appendreads 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 sayin— 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 islen(). 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
.appendand.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
SUMandCOUNTare the accumulate pattern.
📖 Lesson-Specific Vocabulary
[start:stop:step]. Stop is EXCLUSIVE.in operator — Membership test. Returns True/False.🗝️ Lesson 2 · Dictionaries
Lesson 2 · Dictionaries
Lesson PlanAt-a-Glance
d[key], add/update/delete entries, and use .get() for safe lookups that don't crash on missing keys..get()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 upages[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"])→KeyErrorCRASH
- 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"]
- Update:
- 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:"p["age"] = 15p.get("phone", "N/A")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
contact[0] on a dict. Crashes with KeyError: 0.contact[name] instead of contact["name"]. Either crashes (NameError if no variable called name) or returns wrong value (if there IS such a variable).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..get() always returns None."None back when keys are missing..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..add(). (There isn't one.)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.{"name": "Alex", "name": "Sam"} and is surprised the dict only has one entry.{"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 functionbuy(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 withcontact["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
🪆 Lesson 3 · Looping Dicts & Nested Data
Lesson 3 · Looping Dicts & Nested Data
Lesson PlanAt-a-Glance
.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..keys(), .values(), .items(), Nested Datausers[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).
- Find the max: loop
🎤 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"]whenstudentsis a LIST of dicts. They needstudents[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:"- "Alex's name."
- "Sam's first score."
- "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
for x in dict gives values."for s in scores: print(s) — student expects scores; gets names. Confusion..values(). To get both, use .items(). The default behavior is the surprising one — drill it..items() in favor of two separate loops.".items()..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.students["name"] when students is a list. Or contact[0] when contact is a dict. Off by one level.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.scores.items() and calling del scores[key] inside. Crashes with RuntimeError: dictionary changed size during iteration.for k in list(scores.keys()):) or build a NEW dict via filter pattern.data["alex"] on a 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
🔒 Lesson 4 · Tuples
Lesson 4 · Tuples
Lesson PlanAt-a-Glance
Lesson Flow (45 minutes)
🔥 Warm-Up (5 min)
- Project:
location = [40.7, -74.0] # latitude, longitude. Ask: "What if a programmer accidentally writeslocation[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 parenspoint = 3, 5— tuple without parens (commas make a tuple)point[0]→ 3 (indexing works)point[0] = 10→TypeErrorCRASH (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.
- Lists: mutable, square brackets, methods like
- Walk through Section 3 ("Tuple Unpacking — A Genuine Superpower"). Live-code:
x, y = (3, 5)— assigns x=3, y=5 in one linename, age = "Alex", 13— same idea, no parens neededdef min_max(nums): return min(nums), max(nums)thenlo, 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
.appendon a tuple. Crashes withAttributeError. The fix is to convert to a list first if needed:lst = list(my_tuple).
🚪 Exit Ticket (5 min)
- On paper:
- "Will the line
t = (1, 2, 3); t[0] = 99work? Why or why not?" - "Write a tuple representing your home as (city, state)."
- "Will the line
- Answers: 1) Crashes — tuples are immutable.
t[0] = 99isn't allowed. 2) Anything like("Savannah", "GA")works.
⚠️ Watch For — Common Misconceptions
x, y = 3, 5 works without parens.3, 5 is a tuple. (3, 5) is the same tuple. Use parens for clarity, especially in function returns.t = (5). Student thinks they made a 1-item tuple. They didn't — that's just 5 in parens.t = (5,). The comma is the tuple-maker. Annoying syntax wart but unavoidable.t = (1, 2) followed by t = (3, 4) works fine.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).🎯 Differentiation
For early finishers
Challenge: write a functiondescribe(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
x, y = point.📇 Lesson 5 · Strings & Contact Vault Capstone
Lesson 5 · Strings & Contact Vault
Project PlanAt-a-Glance
.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..split(), .join(), .strip(), CRUDProject 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
name.strip() on a line by itself. Then print(name) still shows leading whitespace. Confusion..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."query.lower() in name.lower(). Drill this pattern. It's universal — every search box in every app does this.contact[0] instead of contact["name"]."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.contact["location"][0] = "Atlanta". Crashes — tuples are immutable.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..strip() input."input() call should be followed by .strip(). name = input("Name: ").strip(). The rubric explicitly requires this — 15 of 100 pts is "String Cleanup."remove_contact loops the vault and calls vault.remove(c). Items get skipped or crashes.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 (skipremove_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.
| Category | What to look for | Pts |
|---|---|---|
| Data Shape | List of dicts; each dict uses name, phone, email, location; location is a TUPLE. | 15 |
| Modular Functions | At least 5 well-named functions, each doing one job. main() wires them. | 20 |
| String Cleanup | Inputs cleaned with .strip(), .lower(), .replace() as appropriate. Search is case-insensitive. | 15 |
| Search & Filter | Search uses substring matching (in) on lowercased names. Returns a list of matches. | 15 |
| Clean Code Style | snake_case names, 4-space indent, spaces around operators, blank lines between functions, docstrings. | 10 |
| SDLC Documentation | Plan comments at top, test case results documented, version notes at bottom. | 10 |
| Works Correctly | All 8 test cases from Stage 3 pass. No crashes on empty/missing data. | 15 |
| TOTAL | 100 | |
🎁 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)usinglocation[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.
📖 Lesson-Specific Vocabulary
.split turns a string into a list; .join turns a list into a string.input().🛠️ 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.
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.
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.
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.
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.
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.
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.
.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).
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.
Watch list — these still happen in Unit 5 capstones:
SyntaxError: expected ':'— missing colon afterdef,if,for, orwhile.TypeError: '>' not supported between instances of 'str' and 'int'— missed anint()wrap on input.- Functions returning
Nonewhen expected a value —printinstead ofreturn. 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.
[ or a ").
— End of Unit 5 Teacher's Guide —
