Back to the Introduction to Computer Science outline The Course Maker
Introduction to Computer Science outline
Week 10 · Lecture outline

Week 10 — Lecture Outline · Tuples, Dictionaries & Sets

Introduction to Computer Science · CSCI 1101 Fall 2026 · Prof. Okafor Fictional sample

Course: Introduction to Computer Science — CS1 / Programming Fundamentals in Python (CSCI 1101) · Silver Oak University (fictional sample) · Prof. Okafor
Objective covered: Objective 6 — Use Python's core collections; this week: tuples (and immutability), dictionaries (key → value lookup, .get(), KeyError), and sets (uniqueness/membership), and choose the right collection.
SLOs touched: A (write and run a correct program) · B (trace code and predict dict/set/tuple results; find and fix a defect)
Meeting pattern: 2 studio sessions × 75 min = 150 min. Segment minutes below total ~150; scale to your own pattern.

Every code output, traced value, and error message in this outline was produced by actually running the code in Python — not hand-traced. Run them live in class; the outputs are exact. (The set-printing results are the kind most people — and most chatbots — get wrong by assuming order; we ran them. Note: a set's print order is not something to memorize — sets are unordered; the small-integer sets shown here happen to print in a stable order, but the lesson is "duplicates are gone," not "this is the order.")


Week at a Glance

The week's big question "When you have a pile of data, which container should you reach for — a list, a tuple, a dictionary, or a set — and how do you look things up without crashing?"
By the end of the week, students can… (1) use a tuple (a, b), index and unpack it, and explain immutability (assigning to an element raises a TypeError); (2) build a dictionary {key: value}, look up d[key], add/update, use .get(), .keys(), .values(), .items(), and iterate it; (3) avoid a KeyError with .get() or in; (4) use a set to dedupe and test membership, and explain why sets are unordered; (5) choose list vs. tuple vs. dict vs. set for a job.
Key vocabulary tuple, immutable, immutability, TypeError, unpacking, dictionary/dict, key, value, key-value pair, lookup, d[key], add/update, .get(), default, .keys(), .values(), .items(), in (membership), KeyError, set, unique, dedup/deduplicate, unordered, set(), choosing a collection
Materials slides (Deck 10), the week's readings + video links, a free online Python environment + Python Tutor (links in the readings), one approved chatbot (Gemini / Claude / ChatGPT) for the AI-critique moment and the tutorial
Timing note 8 segments, ~150 min total. Session 1 = Segments 1–4 (~75). Session 2 = Segments 5–8 (~75). This is a studio: build the dictionary and set on the projector and have students type every example into the online environment with you, then run it.

Segment 1 — Hook & the Promise (8 min) · Session 1 opens

Hook. Hold up a phone book (or put a picture of one on the slide). "If I want Ada's number, do I read the book from page 1 looking at every number until I find hers? No — I look her up by name." That's the whole idea of a dictionary: you don't find things by position (like a list's index), you find them by a key (a name, a word, an ID). Then put up a guest list with a name written twice and crossed out once: "A guest list doesn't need duplicates — each person counts once." That's a set. And a coordinate (40.7, -74.0): "These two numbers belong together and should never change." That's a tuple.

The promise (write it on the board): "By Friday you'll build a phone book in code and look people up by name, dedupe a messy list down to its unique values in one line, and crash a program on purpose two ways — then fix both. And you'll know the question a real programmer asks first: which collection fits this job?"

Why it matters line (memory hook): "A list finds things by position; a dictionary finds things by name (a key)."


Segment 2 — Tuples & Immutability (18 min)

Plain language first. A tuple is like a list — an ordered group of values — but written with parentheses instead of square brackets, and with one giant difference: a tuple can't be changed after you make it. That property has a name: it's immutable. Use a tuple when a group of values belongs together and should stay fixed — a point (x, y), a date (year, month, day), an RGB color (255, 0, 0).

Build and read one (code-along — everyone types and runs):

point = (3, 4)
print(point)
print(point[0])
print(point[1])
print(len(point))

Output (run-verified):

(3, 4)
3
4
2

"Indexing is exactly like a list and a string — point[0] is the first item. The parentheses are the only syntax change."

Unpacking — pull a tuple apart into names (very common):

point = (3, 4)
x, y = point
print(x)
print(y)

Output (run-verified):

3
4

"x, y = point hands the first value to x and the second to y in one line. You've actually been doing tuple unpacking since Week 2 every time you wrote a, b = 1, 2."

The signature move — try to change it, and watch Python refuse (run it!):

point = (3, 4)
point[0] = 9

Run-verified error:

TypeError: 'tuple' object does not support item assignment

"A list would have happily let us do nums[0] = 9 last week. A tuple says no — that's immutability. The error type is a TypeError: we tried to do something to a type that doesn't allow it. If you need to 'change' a tuple, you build a new one: point = (9, 4)."

The one gotcha to name (a single-item tuple needs a comma):

single = (5,)
print(len(single))

Output (run-verified):

1

"(5) is just the number 5 in parentheses; (5,) — with the trailing comma — is a one-item tuple. Rare, but it surprises people."


Segment 3 — Dictionaries: Look Up by Key (the code-along) (26 min)

Set it up: "Now the most useful collection in Python: the dictionary. Open the editor — we're going to build a phone book and look people up by name."

Plain language first. A dictionary stores pairs: each pair is a key and a value. You write it with curly braces and colons: {key: value, key: value}. You look up a value by its key — phone["Sam"] — the same way you'd flip to "Sam" in a phone book. Keys are usually strings or numbers; values can be anything.

Build a phone book and look people up (code-along, step by step):

Step 1 — create it and print it:

phone = {"Sam": 5551234, "Ada": 5559876}
print(phone)

Output (run-verified):

{'Sam': 5551234, 'Ada': 5559876}

Step 2 — look up a value by its key:

print(phone["Sam"])

Output:

5551234

"phone["Sam"] means 'give me the value stored under the key Sam.' This is the dictionary's whole job — fast lookup by name."

Step 3 — add a new pair (just assign to a new key):

phone["Mo"] = 5552020
print(phone)

Output:

{'Sam': 5551234, 'Ada': 5559876, 'Mo': 5552020}

Step 4 — update an existing key (assigning to a key that already exists replaces its value):

phone["Sam"] = 5550000
print(phone)

Output:

{'Sam': 5550000, 'Ada': 5559876, 'Mo': 5552020}

"Adding and updating look identical — dict[key] = value. If the key is new, it's added; if it already exists, its value is replaced. There's only ever one value per key."

Step 5 — len, membership with in, and the safe lookup .get():

print(len(phone))
print("Ada" in phone)
print("Kai" in phone)
print(phone.get("Ada"))
print(phone.get("Kai"))

Output (run-verified):

3
True
False
None

Wait — that's only four lines of output for five prints. The fifth, phone.get("Kai"), printed a blank line? No — print(None) shows the word None. Here is the full run-verified output:

3
True
False
5559876
None

"in checks whether a key is present (not a value). .get("Kai") returns None for a missing key instead of crashing — that's the seatbelt we'll need in Segment 5."

The dictionary cheat-sheet — put it on a slide:
| Operation | Code | Result |
|---|---|---|
| look up a value | d[key] | the value (or KeyError if missing) |
| add / update | d[key] = value | adds if new, replaces if it exists |
| safe lookup | d.get(key) / d.get(key, default) | value, else None / default |
| is this key here? | key in d | True / False |
| how many pairs | len(d) | the count |
| all the keys / values | d.keys() / d.values() | the keys / the values |


Segment 4 — Iterating a Dictionary (16 min) · Session 1 closes (~75)

Set it up: "A dictionary is most useful when you walk through it. Looping over a dictionary gives you its keys."

Iterate the keys (code-along):

ages = {"Sam": 20, "Ada": 22}
for name in ages:
    print(name)

Output (run-verified):

Sam
Ada

"A plain for name in ages: hands you each key. (Dictionaries remember the order you inserted keys — that's a guarantee since Python 3.7 — so this order is reliable. A set will not give you that, as we'll see.)"

Get the value too, with .items():

ages = {"Sam": 20, "Ada": 22}
for name, age in ages.items():
    print(name, age)

Output (run-verified):

Sam 20
Ada 22

.keys() and .values() (wrap in list() to see them plainly):

ages = {"Sam": 20, "Ada": 22}
print(list(ages.keys()))
print(list(ages.values()))

Output (run-verified):

['Sam', 'Ada']
[20, 22]

Worked trace — predict, then run (build a word-count dictionary): "We count how many times each color appears."

words = ["red", "blue", "red", "red", "blue"]
counts = {}
for w in words:
    counts[w] = counts.get(w, 0) + 1
print(counts)
  • Trace: start with an empty dict {}. "red": counts.get("red", 0) is 0, so counts["red"] = 1. "blue": 0 + 1 = 1. "red" again: counts.get("red", 0) is now 1, so 2. "red" again → 3. "blue" again → 2.
  • Predicted output: {'red': 3, 'blue': 2}. Run it. Actual output (run-verified):
{'red': 3, 'blue': 2}

"This counts.get(w, 0) + 1 pattern — 'whatever's there, or 0 if it's new, plus one' — is the single most common dictionary idiom in all of programming: counting/tallying. .get(w, 0) is what keeps the first time we see a word from crashing with a KeyError."


Segment 5 — The KeyError (and how .get() saves you) (20 min) · Session 2 opens

Hook back in: "Last session you built a phone book. Today you'll crash it on purpose — because the KeyError is the dictionary bug, and the fix is a one-liner you'll use forever."

Plain language first. If you look up a key that isn't in the dictionary with square brackets, Python doesn't return blank or None — it stops and raises a KeyError.

Live demo — the crash (run it):

ages = {"Sam": 20}
print(ages["Ada"])

Run-verified error:

KeyError: 'Ada'

"'Ada' isn't a key, so Python raises KeyError: 'Ada'. Read it bottom-up like every error: the last line names it. This is the trap everyone's first guess gets wrong — people expect None. Square-bracket lookup on a missing key crashes."

Fix #1 — .get() with a default (no crash):

ages = {"Sam": 20}
print(ages.get("Ada"))
print(ages.get("Ada", 0))

Output (run-verified):

None
0

".get("Ada") returns None; .get("Ada", 0) returns the fallback 0. Use .get() whenever a key might be missing."

Fix #2 — check with in before you look up:

ages = {"Sam": 20}
if "Ada" in ages:
    print(ages["Ada"])
else:
    print("not found")

Output (run-verified):

not found

Misconception + cure:
- ❌ "Looking up a missing key gives me None."
Cure: square brackets crash with a KeyError. Only .get() returns None. When in doubt, run itprint(ages["Ada"]) vs print(ages.get("Ada")) are two different stories.


Segment 6 — Sets: Uniqueness, Dedup & Membership (18 min)

Set it up: "Last collection: the set. A set is an unordered bag that automatically refuses duplicates. Two superpowers: dedupe a list in one line, and lightning-fast membership tests."

Dedupe — the signature one-liner (code-along, predict first):

print({1, 2, 2, 3})
  • Predicted: the set drops the repeat. Run it. Actual output (run-verified):
{1, 2, 3}

"You typed 2 twice; the set keeps one. A set holds only unique values."

Turn a messy list into its unique values:

nums = [1, 2, 2, 3, 3, 3]
print(set(nums))
print(len(set(nums)))

Output (run-verified):

{1, 2, 3}
3

"set(nums) is the cleanest dedupe in Python; len(set(nums)) counts the distinct items. (How many unique visitors? len(set(visitor_ids)).)"

Membership — fast in:

s = {1, 2, 3}
print(2 in s)
print(5 in s)

Output (run-verified):

True
False

The headline warning — sets are UNORDERED (put it on a slide, big):
"A set has no positions — there is no s[0], and you must not rely on the order it prints in. For these tiny integer examples the order happens to look tidy, but that's luck, not a rule. The moment you need order, use a list. The thing a set guarantees is what's in it, never the order. This is exactly what chatbots forget — they'll confidently print a string set in 'the order you typed it.' Don't trust it; if order matters, don't use a set."

The empty-braces gotcha:

x = {}
print(type(x))

Output (run-verified):

<class 'dict'>

"{} is an empty dictionary, not an empty set — Python reserved {} for dicts. An empty set is set(). Worth knowing so it doesn't bite you."


Segment 7 — Choosing the Right Collection + Quick Interaction (20 min)

Land the headline skill — put this table on a slide and walk every row:

Collection Looks like Ordered? Changeable? Reach for it when…
list [1, 2, 3] yes (by index) yes you need an ordered sequence you'll add to, remove from, or reorder (scores, a playlist, a queue)
tuple (1, 2) yes (by index) no (immutable) a fixed group that shouldn't change (a coordinate, a date, an RGB color)
dict {"a": 1} keeps insertion order yes you look things up by a key/name (a phone book, word counts, settings, a price list)
set {1, 2, 3} no yes (add/remove) you want only unique values, or fast membership tests (dedupe, "have I seen this ID?")

"Two questions settle almost every choice: (1) Do I look things up by a name/label? → dictionary. (2) Do I just need the unique values? → set. Otherwise it's a list (changeable order) or a tuple (fixed)."

Interaction — "which collection?" rapid-fire (~6 min): put four jobs on a slide; students pick the collection solo (20 sec each), then discuss:
- "Store each student's grade by their name." → dict (look up by name)
- "Keep the unique tags used across all posts." → set (unique)
- "A GPS coordinate that won't change." → tuple (fixed pair)
- "A to-do list you reorder all day." → list (ordered + changeable)

Interaction — Predict-then-Run (~6 min): put four programs on a slide; students predict each output solo (30 sec), compare with a neighbor (1 min), then you run all four. Suggested with run-verified outputs:

print(len({3, 3, 4, 5, 5}))                       # 3
d = {"pen": 3}; d["pen"] = d["pen"] + 2; print(d["pen"])   # 5
caps = {"France": "Paris", "Japan": "Tokyo"}; print(caps["Japan"])  # Tokyo
print({2, 4, 4, 6})                                # {2, 4, 6}

Tally how many the room got — celebrate any miss on the set items as "this is why we run code (and why we never trust a set's order)."


Segment 8 — Technology Workflow + AI-Critique, Callback & Hand-off (18 min) · Session 2 closes (~75)

Technology workflow — watch a dictionary fill up:
1. Open the free online Python environment (link in the readings). Build a dictionary, look up a key, run a set(...) dedupe; read what comes back.
2. To watch a dictionary grow, paste into Python Tutor and click forward:
python counts = {} for w in ["red", "blue", "red"]: counts[w] = counts.get(w, 0) + 1 print(counts)
You'll see the dictionary box gain 'red': 1, then 'blue': 1, then watch 'red' tick up to 2. That growing key→value box is the lesson.

AI-critique moment (students verify, not consume):

Paste this to an approved chatbot: "In Python, what does each of these print? (a) print({3, 1, 2, 1}) (b) ages = {'Sam': 20} then print(ages['Ada']) (c) print({'x': 1, 'y': 2}.get('z', 0)). Give the exact output of each."
Then check by running all three yourself. Two traps: for (a), the model often prints the set in the order you typed it or "sorted" and states it confidently — a set is unordered, so don't trust the order it claims. For (b), it may invent a number or say None — it's actually a KeyError (a crash). Your job all semester: the tool drafts, you run it and judge. This week's blind spots are set ordering and pretending a missing key is fine.

Callback + tease:
- Callback: "Today: tuples (immutable — point[0] = 9 is a TypeError); dictionaries (look up by key, add/update, .get() to dodge the KeyError, iterate with .items()); sets (dedupe, membership, unordered); and the headline — choose the collection that fits the job."
- Tease next week: "We've spent two weeks on collections. Next week we go deep on the collection you've used since Day 1 without thinking about it: strings. You'll meet string methods (.upper(), .split(), .strip(), .replace()), learn to parse and build text, and write your first simple text-processing programs — and a string, it turns out, is a lot like an immutable sequence you already understand."

Hand-off (the week's graded work):
- Lecture Tutorial 10 (AI tutor, share-link submission) — tuples & immutability, dictionaries (lookup, .get(), KeyError), sets, and choosing a collection.
- Quiz 10, Discussion 10 ("Open Source vs. Proprietary: Should Code Be Free or Owned?"), and Assignment 10 ("Build a Lookup, Dedupe a List").
- Coding Lab 10 — "Map It, Dedupe It, Lock It" — build a dictionary and a set, run a predict-then-run table, fix a KeyError and a tuple-mutation bug, and watch a dictionary fill up in Python Tutor.


Instructor FAQ — Common Stumbles

Student says / does Quick cure
"I looked up a key and it crashed." A missing key with d[key] raises KeyError. Use d.get(key) (returns None) or check if key in d first.
Expects d["missing"] to return None. Square brackets crash; only .get() returns None. Run both side by side to feel the difference.
Tries point[0] = 9 on a tuple. Tuples are immutableTypeError: 'tuple' object does not support item assignment. Build a new tuple instead.
Thinks a set keeps the order you typed. Sets are unordered — there's no s[0], and the print order isn't reliable. Need order? Use a list.
Writes {} for an empty set. {} is an empty dict. An empty set is set().
Uses a list as a dictionary key. Keys must be immutable (strings, numbers, tuples) — a list can't be a key. (A tuple can.)
Confuses "key in dict" with "value in dict". key in d checks keys, not values. That's almost always what you want.
"I'll trust the chatbot's printed set." This week chatbots miss set ordering constantly and fake dict values. Run it and read what Python prints.

Scope flag

This outline stays within Objective 6, the second collections week (tuples & immutability; dictionaries — lookup, add/update, .get(), .keys()/.values()/.items(), iteration, KeyError; sets — dedup, membership, unordered; choosing a collection). It uses only this-week and prior-week constructs — for loops (Week 6), if/else (Week 4), lists and indexing (Weeks 3, 9), and reading errors (Week 1). Strings in depth are Week 11 and only teased here; dict/set comprehensions, set algebra (|, &, -), del, defaultdict/Counter, nested dictionaries, and using tuples as dictionary keys beyond a passing mention are out of CS1 scope. Python and its type/method/exception names (dict, set, .get, TypeError, KeyError, …) are referenced factually; the instructor and institution remain fictional. Every output shown was produced by running the code.

~ Prof. Okafor's edition · Fall 2026 · built with thecoursemaker.com