Collections
- Choose the right structure โ list, tuple, set, or dict โ for a given job and justify it
- Index and slice lists and strings without off-by-one errors
- Explain aliasing: predict when two names see the same mutation
- Build and query dicts, including safe lookup with .get and iteration over items
- Rewrite simple loops as list and dict comprehensions
| Spaced-rep warm-up: Days 1โ3 flashcards | 10 min |
| Concept study: ELI5 + tech, with the cells-index visualizer | 20 min |
| Guided: shelf lab, aliasing lab, dicts & comprehensions | 45 min |
| Practice: the gradebook | 20 min |
| Project: study-log data model | 15 min |
| Quiz + flashcards | 10 min |
Builds on: Day 2 โ Variables, types, and loops ยท Day 3 โ Functions and return values
A list is a bookshelf: books in a fixed order, each slot numbered (starting at 0, the ground floor), and you fetch a book by its position โ "give me shelf slot 2." You can add books, remove them, or swap one out; the shelf itself stays put. A tuple is a shelf sealed behind glass: same idea, but nothing can be added or swapped after it's built โ great for things that must not change. A dict works like a real dictionary: you don't ask for "the word on page 305," you ask for "the definition of *serendipity*" โ you look things up by a meaningful key, not a position. And a set is a bag that refuses duplicates: throw in "apple" twice, it keeps one โ perfect for "have I seen this before?"
One warehouse warning from Day 2's labels-on-boxes: two labels can point at the *same shelf*. If your friend rearranges the books using their label, your label sees the rearranged shelf too โ because there is only one shelf. That's aliasing, and it's today's most valuable lesson.
Choosing structures is half of programming. The interview classic "why is your code slow?" is usually "you used a list where a set/dict belonged" โ that exact trade-off gets a price tag on Day 22 (Big O) and powers the hashing patterns of Day 23. Everything you'll touch as an AI engineer is nested lists-and-dicts: every JSON API response (Day 41), every LLM chat request โ a list of message dicts (Day 106) โ every RAG chunk with its metadata (Day 114). Aliasing bugs, meanwhile, are the classic "my function mysteriously changed my caller's data" production incident. Learn to see references today and that bug loses its magic.
The bookshelf โ indexing and slicing a list
step 1 / 6A list is a numbered shelf. Positions start at 0 โ the first item is langs[0], not langs[1].
Guided practice
The shelf lab โ indexing, slicing, mutating
15 min- Create
week-01/shelves.pywith the starter code. Before running each section, write your predicted output as a comment โ the visualizer view (cells-index) shows the numbered slots if you want to check your mental picture. - Section 1: verify the negative-index and slicing predictions. Then answer in a comment: why does nums[1:3] contain two items, not three?
- Section 2: run the sort trap. Explain in a comment what mystery is and why.
- Section 3: practice mutations โ append a value, pop the last, insert at the front, remove by value. Print after each so you can watch the shelf change.
- Finish with: build a list of the first 10 square numbers using a loop and .append(). Keep it โ you'll rewrite it as a comprehension in exercise 3.
One shelf, two labels โ the aliasing lab
15 min- Create
aliasing.pywith the starter code. This is the most important 15 minutes of the week โ go slowly and predict before every print. - Section 1: a and b are two labels on ONE list. Confirm both names see the append. Then check
a is b(True) versus the copied c:a == c(True) buta is c(False) โ same contents, different shelves. - Section 2: the function-mutates-argument trap. The caller's list changed even though the function never returned anything. Write one sentence: why? (Hint: the parameter is another label on the same shelf.)
- Section 3: shallow copy โ the outer list was copied, the inner list is still shared. Sketch the two shelves on paper with an arrow to the shared inner list; this diagram IS the mental model.
- Fix the function in section 2 so it does NOT mutate its input: make a copy inside, or better, build and return a new list. Professional default: functions don't surprise their callers.
Dicts, sets & comprehensions in anger
15 min- Create
lookup.pywith the starter code. Section 1 builds the classic word-frequency counter โ the single most reused dict pattern in this program (it returns in Day 23's hashing patterns and Day 96's tokenizer lab). - Trace the .get(word, 0) + 1 line by hand for the first three words, writing the dict's state after each. This trace is the lesson.
- Section 2: sets โ dedupe the word list and test membership. Add a check: which words appear more than once? (Every word whose count is > 1.)
- Section 3: comprehensions. Rewrite your squares loop from exercise 1 as a comprehension, then build a dict comprehension mapping each word to its length, then filter: words longer than 3 letters.
- In a final comment, answer: for looking up a user's age by name, why is a dict the right shelf and a list of pairs the wrong one?
On your own
The gradebook
20 minBuild gradebook.py from a blank file.
Goal: start from grades = {"ada": [92, 88, 99], "grace": [85, 91, 78], "alan": [70, 95, 88]}. Write three functions: average(scores) returns the mean of a list; report(grades) returns a NEW dict mapping each name to their average (dict comprehension encouraged); top_student(grades) returns the name with the highest average. Print a formatted line per student plus a winner line.
Constraints: no function may mutate the grades dict; averages computed with sum() and len(), not hand-typed; use .items() for iteration.
Hints (only if stuck): top_student can loop over report(grades).items() keeping a best-so-far name and score โ the same keep-the-best shape as Day 2's guessing game logic.
Study-log data model
Design the data structure your task tracker (Day 7) will be built on. Create studylog.py holding a list of dicts, one per completed day so far, e.g. {"day": 1, "title": "Your Machine, Your Map", "minutes": 120, "topics": ["setup", "repl"]} โ fill in your real Days 1โ3, estimating minutes honestly. Write functions: add_day(log, day, title, minutes, topics) (appends and returns the log), total_minutes(log), find_day(log, day_number) (returns the dict or None), and all_topics(log) (returns a sorted list of unique topics across all days โ a set does the dedupe). Demo all four under a main guard. This list-of-dicts shape is exactly how you'll hold tasks on Day 7, rows from a database on Day 36, and chat messages on Day 106.
Common mistakes & misconceptions
- Writing b = a and believing you copied the list. You copied the LABEL; both names point at one object. Use .copy(), a[:], or list(a) โ and remember even those are shallow.
- Using x = x.sort() or x = x.append(3). Mutation methods return None, so x becomes None. Either mutate (x.sort()) or rebuild (x = sorted(x)) โ never both.
- Reaching for grades["bob"] when the key might be absent, then crashing with KeyError. Use .get(key, default) when missing is normal; use [] when missing is a bug you WANT to hear about.
- Membership-testing a huge list (x in big_list) inside a loop. Lists scan every element; sets and dicts jump straight there. This becomes the O(nยฒ)-vs-O(n) story of Day 22.
- Mutating a list while looping over it (removing items mid-iteration skips elements). Loop over a copy, or build a new filtered list with a comprehension.
- Using a list as a dict key. Keys must be immutable (hashable) โ use a tuple instead. This is WHY tuples exist alongside lists.
Q1. a = [1, 2]; b = a; b.append(3). What is a?
Q2. You need "have we already processed this ID?" checks on millions of IDs. Best structure?
Q3. What does nums[1:3] return for nums = [5, 6, 7, 8]?
Go deeper โ curated resources
- Python Tutor โ visualize references step by step โ โ Paste the aliasing lab in and watch the arrows: names point at objects. Ten minutes here makes shallow copy permanently obvious.
- All three guided scripts run with written predictions checked against reality
- The shallow-copy diagram sketched and the mutating function fixed
- Gradebook functions work without mutating their input
- studylog.py passes all five rubric checks
- Quiz โฅ 2/3 (redo the aliasing lab if you missed question 1)
โ Back: Day 2 taught that rebinding a label never touches the old box; today added the twist โ MUTATING a shared box changes it for every label. Day 3's "functions shouldn't surprise callers" rule got teeth: passing a list passes a label.
Forward โ: This list-of-dicts model IS Day 7's task tracker, Day 36's database rows, and Day 106's chat messages. The set-vs-list membership gap becomes Day 22's central example and Day 23's hashing lesson. Shallow-vs-deep copying returns when you handle nested API payloads on Day 41.
Unlocks: D5 Strings, Files & Errors ยท D7 Week 1 Checkpoint: CLI Task Tracker ยท D9 Object-Oriented Python I ยท D10 Object-Oriented Python II