Session 15 - Tuples & Unpacking

Session 15 of the Python Fundamentals series, covered in depth. Tuples are immutable, ordered sequences, and the session covers creating them with (a, b), the trailing-comma rule for a single element, packing and unpacking, multiple assignment, swapping in one line, unpacking tuples in for loops, returning several values from a function, and star unpacking with *rest. It explains why immutability matters, since it gives safe fixed records and lets a tuple serve as a dictionary key, and when to reach for a tuple rather than a list. The traps are that (x) is not a tuple, that reassigning t[0] raises a TypeError, and that unpacking the wrong number of values raises a ValueError. Every snippet and error message was executed and copied verbatim from CPython 3.12.

Subject: Python Fundamentals · 100 slides · code lesson

Open the interactive version of this deck · Homework for this lesson

What this lesson covers

The lesson, slide by slide

1. Tuples & Unpacking

Title

Python Fundamentals - Session 15

Fixed records, multiple values at once, and the trailing comma that trips everyone up

2. What you will be able to do

Objectives

Lists hold things that change. A tuple holds a fixed group of values that belong together. By the end you can:

  1. Create a tuple with (a, b) and read its items by index.
  2. Pack and unpack: a, b = 1, 2, and swap with a, b = b, a.
  3. Unpack tuples inside a for loop and return several values from a function.
  1. Grab the rest with first, *rest = ... star unpacking.
  2. Explain why immutability makes tuples safe records and valid dict keys.
  3. Avoid the three classic traps: the missing trailing comma, t[0] = ..., and unpacking the wrong count.

3. What survived from Session 14 - Capstone: Adventure Game (Part 2)?

Warm-up

Discussion prompt

Before we open Session 15 - Tuples & Unpacking: without looking back, what was the main idea of Session 14 - Capstone: Adventure Game (Part 2), and what could you do by the end of it that you could not do before?

Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.

Answer:

That session keeps state in a dictionary, adds an inventory and a score, makes decisions from that state, and builds real winning and losing endings, then polishes and extends the game.

4. What a Tuple Is

Section

Part 1

5. A tuple is an ordered, unchangeable group

Concept

A tuple stores several values in order, just like a list - but once made, it cannot be changed.

tuple — An ordered, immutable sequence of values, written with commas and usually round brackets: (3, 4). Immutable means you cannot add, remove, or replace items after it is built.

6. Break it if you can: A tuple is an ordered, unchangeable group

Counterexample

Discussion prompt

A tuple stores several values in order, just like a list - but once made, it cannot be changed.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

7. The comma is what makes a tuple

Concept

It is the commas, not the brackets, that build a tuple. The () just group it for readability.

point = (3, 4) makes a tuple of two values. You read items by index with [ ], exactly like a list.

8. By analogy: The comma is what makes a tuple

Analogy

Discussion prompt

Explain The comma is what makes a tuple by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

point = (3, 4) makes a tuple of two values. You read items by index with [ ], exactly like a list.

9. What has to happen first: Make a tuple and read it

Ranking

Put in order

Put the moves of Make a tuple and read it into the order they have to happen.

  1. Line 1 packs 3 and 4 into one tuple
  2. Index with [0] and [1] just like a list
  3. Read the output

Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. point is a single value that holds two numbers in order.

10. Make a tuple and read it

Worked example

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

Line 1 packs 3 and 4 into one tuple

Why: point is a single value that holds two numbers in order.

Index with [0] and [1] just like a list

Why: Indexing reads an item; it does not change the tuple.

Read the output

Why: Verified by execution: the whole tuple, then each item, then its type.

expressionvalue
point(3, 4)
point[0]3
point[1]4
type(point)<class 'tuple'>

11. Fill in: value for Make a tuple and read it

Comparison

Comparison matrix

From Make a tuple and read it: refill the value column from what you know. The rest of the table is as it appeared.

expressionvalue
point(3, 4)
point[0]3
point[1]4
type(point)<class 'tuple'>

12. A tuple is a sealed label

Intuition

Picture a shipping label already printed and sealed: a name and a date, side by side, in a fixed order.

You can read what is on the label all day, but you cannot cross out the name and write a new one. To change it, you print a fresh label. That is a tuple.

13. Teach it back: A tuple is a sealed label

Explain it

Discussion prompt

Explain A tuple is a sealed label to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

Picture a shipping label already printed and sealed: a name and a date, side by side, in a fixed order.

14. One item needs a trailing comma

Concept

For a one-item tuple you must add a comma: (5,). Without it, (5) is just the number 5 in ordinary brackets.

Remember: the comma makes the tuple, so a lone value with no comma is not a tuple at all.

15. Plan first: (5,) versus (5)

Step zero

Discussion prompt

(5,) versus (5) — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.

Hint: It starts with: The trailing comma on line 1 builds a tuple

Answer:

  1. The trailing comma on line 1 builds a tuple
  2. No comma on line 2 means plain brackets
  3. Read the output

16. (5,) versus (5)

Worked example

one = (5,)
not_a_tuple = (5)
print(one, type(one))
print(not_a_tuple, type(not_a_tuple))

The trailing comma on line 1 builds a tuple

Why: (5,) is a one-item tuple; the comma is doing the work.

No comma on line 2 means plain brackets

Why: (5) is just 5 - the brackets only group, they do not make a tuple.

Read the output

Why: Verified by execution: one is a tuple, not_a_tuple is an int.

namevaluetype
one(5,)<class 'tuple'>
not_a_tuple5<class 'int'>

17. What each one costs: (5,) versus (5)

Trade off

Comparison matrix

From (5,) versus (5): every row here is a choice with a cost. Fill the value column, then say which row you would actually pick and what you give up for it.

namevaluetype
one(5,)<class 'tuple'>
not_a_tuple5<class 'int'>

18. Something is wrong here: forgetting the trailing comma

Anomaly

Predict first

A student writes this, and it looks reasonable:

You mean a one-item tuple, but write plain brackets.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Without the comma, the brackets just group a number, so y is the int 5 - later code that expects a tuple will misbehave.

Add the trailing comma.

Why: Without the comma, the brackets just group a number, so y is the int 5 - later code that expects a tuple will misbehave.

19. Trap: forgetting the trailing comma

Trap

The trap

You mean a one-item tuple, but write plain brackets.

y = (5)
print(y, type(y))

(5) is not a tuple

Why: Without the comma, the brackets just group a number, so y is the int 5 - later code that expects a tuple will misbehave.

you writey istype
(5)5<class 'int'>

The fix

Add the trailing comma.

x = 5,
print(x, type(x))

5, makes a one-item tuple

Why: The comma builds the tuple - brackets are optional. Real output: (5,) and <class 'tuple'>. Rule of thumb: a single trailing comma is the whole difference.

you writex istype
5,(5,)<class 'tuple'>

20. Break it on purpose: forgetting the trailing comma

Break the constraint

Discussion prompt

The rule this trap just fixed:

The comma builds the tuple - brackets are optional. Real output: (5,) and <class 'tuple'>. Rule of thumb: a single trailing comma is the whole difference.

Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?

Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.

Answer:

Without the comma, the brackets just group a number, so y is the int 5 - later code that expects a tuple will misbehave.

21. Packing & Unpacking

Section

Part 2

22. Packing: several values into one tuple

Concept

Write values separated by commas and Python packs them into a tuple - brackets optional.

packed = 1, 2, 3 and packed = (1, 2, 3) mean the same thing.

23. Unpacking: one tuple into several names

Concept

Put matching names on the left and Python unpacks the tuple, one value per name, in order.

unpacking — Assigning the items of a sequence to several variables at once: a, b, c = (1, 2, 3) sets a=1, b=2, c=3. The count on the left must match the count on the right.

24. Take the definitions apart: tuple vs unpacking

Definition probe

Sort into buckets

Every line below is part of the definition of tuple or of unpacking — one or the other, never both. Put each where it belongs.

tuple
An ordered, immutable sequence of values, written with commas and usually round brackets; Immutable means you cannot add, remove, or replace items after it is built.
unpacking
Assigning the items of a sequence to several variables at once; a, b, c = (1, 2, 3) sets a=1, b=2, c=3.; The count on the left must match the count on the right.
b1
An ordered, immutable sequence of values, written with commas and usually round brackets: (3, 4). Immutable means you cannot add, remove, or replace items after it is built.
b2
Assigning the items of a sequence to several variables at once: a, b, c = (1, 2, 3) sets a=1, b=2, c=3. The count on the left must match the count on the right.

25. What has to happen first: Pack, then unpack

Ranking

Put in order

Put the moves of Pack, then unpack into the order they have to happen.

  1. Line 1 packs three values
  2. Line 3 unpacks it into a, b, c
  3. Read the output

Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. No brackets needed - the commas pack 1, 2, 3 into one tuple.

26. Pack, then unpack

Worked example

packed = 1, 2, 3
print(packed, type(packed))
a, b, c = packed
print(a, b, c)

Line 1 packs three values

Why: No brackets needed - the commas pack 1, 2, 3 into one tuple.

Line 3 unpacks it into a, b, c

Why: Three names on the left take the three items in order.

Read the output

Why: Verified by execution: the tuple, then its three items spread across names.

stepresult
packed(1, 2, 3)
a1
b2
c3

27. Inspect it line by line: Pack, then unpack

Error analysis

Annotate

Walk the callouts on Pack, then unpack. Each one is a place this is easy to get subtly wrong.

  • No brackets needed - the commas pack 1, 2, 3 into one tuple.
  • Three names on the left take the three items in order.
  • Verified by execution: the tuple, then its three items spread across names.

28. Multiple assignment in one line

Concept

This is why a, b = 1, 2 works: the right side packs (1, 2), the left side unpacks it into a and b.

It is packing and unpacking happening together on a single line - a tidy way to set several variables at once.

29. Two variables at once

Worked example

a, b = 1, 2
print(a, b)

The right side packs (1, 2)

Why: 1, 2 becomes a temporary tuple.

The left side unpacks it

Why: Verified by execution: a is 1 and b is 2, so it prints 1 2.

namevalue
a1
b2

30. Draw the shape of it: Two variables at once

Blank canvas

Draw it

Draw what Two variables at once just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

31. Unpacking is dealing cards

Intuition

The tuple is a small stack of cards in a set order. Unpacking deals them out, one to each player named on the left.

If there are three cards and only two players - or two cards and three players - the deal fails. The counts have to line up. (You will see that failure as a ValueError shortly.)

32. Something is wrong here: wrong number of values to unpack

Anomaly

Predict first

A student writes this, and it looks reasonable:

The count on the left does not match the tuple.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Python has nothing to give c, so it raises a ValueError instead of guessing.

Match the number of names to the number of values.

Why: Python has nothing to give c, so it raises a ValueError instead of guessing.

33. Trap: wrong number of values to unpack

Trap

The trap

The count on the left does not match the tuple.

a, b, c = (1, 2)

Three names, only two values

Why: Python has nothing to give c, so it raises a ValueError instead of guessing.

caseresult
a, b, c = (1, 2)ValueError: not enough values to unpack (expected 3, got 2)
a, b = (1, 2, 3)ValueError: too many values to unpack (expected 2)

The fix

Match the number of names to the number of values.

a, b, c = (1, 2, 3)
print(a, b, c)

Three names, three values

Why: Now every name gets exactly one item. Real output: 1 2 3. Rule of thumb: count both sides, or use a star target (coming up) when the count varies.

namevalue
a1
b2
c3

34. Watch it run: Trap: wrong number of values to unpack

Pattern

Step through it

Step through Trap: wrong number of values to unpack one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: name is a
  2. Step 2: name is b
  3. Step 3: name is c

35. The One-Line Swap

Section

Part 3

36. Swap two variables with no temp

Concept

a, b = b, a swaps the two values in one line. The right side packs the current values first, then unpacks them into the flipped names.

No temporary variable needed - Python evaluates the whole right side before assigning anything.

37. Predict the next row: Swap in one line

Pattern

Predict first

The table runs: start | 10 | 3 · pack right side | 10 | 3

In Swap in one line, given the rows so far: what is the next one — the row where step is after swap?

Correct: after swap | 3 | 10

stepab
start103
pack right side103
after swap310

Why: The relationship between the columns, not the individual numbers, is what generates the next row. b is 3 and a is 10 right now, so it builds (3, 10) before assigning.

38. Swap in one line

Worked example

a, b = 10, 3
print(a, b)
a, b = b, a
print(a, b)

The right side packs (3, 10) first

Why: b is 3 and a is 10 right now, so it builds (3, 10) before assigning.

Then it unpacks into a, b

Why: Verified by execution: a becomes 3, b becomes 10. Prints 10 3 then 3 10.

stepab
start103
pack right side103
after swap310

39. Restore the missing line: The old way, for contrast

Fill the middle

Fill in the blanks

From The old way, for contrast — one line has had its right-hand side removed. Put it back.

a, b = 10, 3
temp = a
a = b
b = temp
print(a, b)

Why: b is what everything below it consumes, so the wrong expression here fails later and somewhere else. Without temp, setting a = b would lose the old a.

40. The old way, for contrast

Worked example

a, b = 10, 3
temp = a
a = b
b = temp
print(a, b)

Save a in temp before overwriting it

Why: Without temp, setting a = b would lose the old a. Three lines do what the swap does in one.

Read the output

Why: Verified by execution: same result, 3 10 - the tuple swap is just shorter and clearer.

stepabtemp
start103-
temp = a10310
a = b3310
b = temp31010

41. Which is which, by a

Discrimination

Sort into buckets

Sort these by a, from memory, without looking back at The old way, for contrast. Telling them apart on the spot is the skill; the table is only where the answer happens to be written down.

10
start; temp = a
3
a = b; b = temp
g1
a is "10" for start, temp = a — that is what the table on "The old way, for contrast" records, and it is the single property separating this group from the rest.
g2
a is "3" for a = b, b = temp — that is what the table on "The old way, for contrast" records, and it is the single property separating this group from the rest.

42. Unpacking in Loops

Section

Part 4

43. A list of tuples

Concept

Data often comes as a list of tuples - each tuple a small record, like a name paired with a score.

Loop over it and unpack each tuple right in the for line: for name, score in scores:.

44. Plan first: Unpack each record in the loop

Step zero

Discussion prompt

Unpack each record in the loop — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.

Hint: It starts with: Each item is a (name, score) tuple

Answer:

  1. Each item is a (name, score) tuple
  2. name, score unpacks it each pass
  3. Trace the passes

45. Unpack each record in the loop

Worked example

scores = [("Ana", 88), ("Ben", 72), ("Cy", 95)]
for name, score in scores:
    print(name, "scored", score)

Each item is a (name, score) tuple

Why: The loop hands one tuple per pass.

name, score unpacks it each pass

Why: Two names catch the two items of the current tuple.

Trace the passes

Why: Verified by execution: one line printed per record.

passnamescoreprints
1Ana88Ana scored 88
2Ben72Ben scored 72
3Cy95Cy scored 95

46. enumerate gives (index, item) tuples

Worked example

colors = ["red", "green", "blue"]
for i, color in enumerate(colors):
    print(i, color)

enumerate pairs each item with its index

Why: Each pass yields a tuple like (0, 'red'), which i, color unpacks.

Trace the passes

Why: Verified by execution: index and value together, no manual counter needed.

passicolorprints
10red0 red
21green1 green
32blue2 blue

47. Watch it run: enumerate gives (index, item) tuples

Pattern

Step through it

Step through enumerate gives (index, item) tuples one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: pass is 1
  2. Step 2: pass is 2
  3. Step 3: pass is 3

48. dict.items() yields (key, value) tuples

Worked example

prices = {"pen": 2, "pad": 5}
for item, price in prices.items():
    print(item, price)

.items() gives a (key, value) tuple per pair

Why: item, price unpacks each one - the same loop-unpacking pattern from Session 8, now named.

Trace the passes

Why: Verified by execution: each key with its value.

passitempriceprints
1pen2pen 2
2pad5pad 5

49. Returning Many Values

Section

Part 5

50. A function can return a tuple

Concept

return a, b packs the values into one tuple and hands it back - a function's clean way to answer with more than one result.

The caller can unpack it straight into names: low, high = min_max(nums).

51. What has to happen first: Return the low and high together

Ranking

Put in order

Put the moves of Return the low and high together into the order they have to happen.

  1. return min(nums), max(nums) packs a tuple
  2. The caller unpacks it into low, high
  3. Or catch the whole tuple in one name

Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. The comma makes one return value that holds both numbers.

52. Return the low and high together

Worked example

def min_max(nums):
    return min(nums), max(nums)

low, high = min_max([4, 9, 1, 7])
print(low, high)
result = min_max([4, 9, 1, 7])
print(result, type(result))

return min(nums), max(nums) packs a tuple

Why: The comma makes one return value that holds both numbers.

The caller unpacks it into low, high

Why: Two names catch the two returned items.

Or catch the whole tuple in one name

Why: Verified by execution: result is the tuple (1, 9). Prints 1 9, then (1, 9) <class 'tuple'>.

stepvalue
min_max([4, 9, 1, 7])(1, 9)
low1
high9
result(1, 9)

53. Which is which, by value

Discrimination

Sort into buckets

Sort these by value, from memory, without looking back at Return the low and high together. Telling them apart on the spot is the skill; the table is only where the answer happens to be written down.

(1, 9)
min_max([4, 9, 1, 7]); result
1
low
9
high
g1
value is "(1, 9)" for min_max([4, 9, 1, 7]), result — that is what the table on "Return the low and high together" records, and it is the single property separating this group from the rest.
g2
value is "1" for low — that is what the table on "Return the low and high together" records, and it is the single property separating this group from the rest.
g3
value is "9" for high — that is what the table on "Return the low and high together" records, and it is the single property separating this group from the rest.

54. Return three stats at once

Worked example

def stats(nums):
    return sum(nums), len(nums), sum(nums) / len(nums)

total, count, average = stats([10, 20, 30])
print(total, count, average)

The function packs three results

Why: sum, count, and average all ride back in one tuple.

Unpack into three named variables

Why: Verified by execution: total 60, count 3, average 20.0. Prints 60 3 20.0.

namevalue
total60
count3
average20.0

55. One parcel, several items

Intuition

A function still hands back exactly one thing. A tuple lets that one thing be a small parcel with several items inside.

The caller can open the parcel item by item (unpack) or keep it sealed and pass it along (one name). Either way, one return, many values.

56. Star Unpacking

Section

Part 6

57. A star grabs the rest

Concept

Put * before one name and it soaks up all the leftover items as a list: first, *rest = ....

This lets you unpack when you only know some of the positions - the star handles the variable middle or tail.

58. first, *rest

Worked example

first, *rest = [10, 20, 30, 40]
print(first)
print(rest)

first takes the head, *rest takes the tail

Why: first is one value; the star collects everything left over.

The starred name is a list

Why: Verified by execution: first is 10, rest is [20, 30, 40] - note rest is a list, not a tuple.

namevaluetype
first10int
rest[20, 30, 40]list

59. Fill in: type for first, *rest

Comparison

Comparison matrix

From **first, rest: refill the type* column from what you know. The rest of the table is as it appeared.

namevaluetype
first10int
rest[20, 30, 40]list

60. *init, last

Worked example

*init, last = [10, 20, 30, 40]
print(init)
print(last)

The star can sit at the front too

Why: *init grabs everything except the final item; last takes the tail.

Read the output

Why: Verified by execution: init is [10, 20, 30], last is 40.

namevalue
init[10, 20, 30]
last40

61. a, *mid, b

Worked example

a, *mid, b = [1, 2, 3, 4, 5]
print(a, mid, b)

Fixed ends, flexible middle

Why: a takes the first item, b the last, and *mid absorbs whatever is between.

Read the output

Why: Verified by execution: a is 1, b is 5, mid is [2, 3, 4]. Prints 1 [2, 3, 4] 5.

namevalue
a1
mid[2, 3, 4]
b5

62. Watch it run: a, *mid, b

Pattern

Step through it

Step through **a, mid, b* one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: name is a
  2. Step 2: name is mid
  3. Step 3: name is b

63. Why Immutability Matters

Section

Part 7

64. You cannot reassign an item

Concept

A list lets you do scores[0] = 90. A tuple does not - trying it raises a TypeError.

That locked-down nature is the whole point: a tuple is a value you promise not to change.

65. Restore the missing line: List changes, tuple record stays put

Fill the middle

Fill in the blanks

From List changes, tuple record stays put — one line has had its right-hand side removed. Put it back.

scores = [88, 72, 95]
scores[0] = 90
print(scores)
record = ("Ana", "2010-05-14")
print(record[0], record[1])

Why: scores is what everything below it consumes, so the wrong expression here fails later and somewhere else. scores[0] = 90 replaces the first item in place.

66. List changes, tuple record stays put

Worked example

scores = [88, 72, 95]
scores[0] = 90
print(scores)
record = ("Ana", "2010-05-14")
print(record[0], record[1])

The list allows item assignment

Why: scores[0] = 90 replaces the first item in place.

The tuple is read-only

Why: Verified by execution: you can read record[0] and record[1], but you cannot reassign them.

expressionvalue
scores[90, 72, 95]
record[0]Ana
record[1]2010-05-14

67. Something is wrong here: trying to change a tuple item

Anomaly

Predict first

A student writes this, and it looks reasonable:

You reach for a list habit and assign into a tuple.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: A tuple cannot be edited in place, so Python raises a TypeError - the assignment never happens.

Build a fresh tuple instead of editing.

Why: A tuple cannot be edited in place, so Python raises a TypeError - the assignment never happens.

68. Trap: trying to change a tuple item

Trap

The trap

You reach for a list habit and assign into a tuple.

color = ("red", "green", "blue")
color[0] = "orange"

Item assignment is not allowed

Why: A tuple cannot be edited in place, so Python raises a TypeError - the assignment never happens.

lineresult
color[0] = "orange"TypeError: 'tuple' object does not support item assignment

The fix

Build a fresh tuple instead of editing.

color = ("red", "green", "blue")
color = ("orange",) + color[1:]
print(color)

Make a new tuple from the pieces

Why: Slicing and joining builds a new tuple; the old one is untouched. Real output: ('orange', 'green', 'blue'). If you truly need in-place edits, use a list.

stepvalue
color[1:]('green', 'blue')
('orange',) + color[1:]('orange', 'green', 'blue')

69. Which of these survive contact with Session 15 - Tuples & Unpacking?

Two truths and a lie

Sort into buckets

Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.

Holds up
A tuple stores several values in order, just like a list - but once made, it cannot be changed.; point = (3, 4) makes a tuple of two values. You read items by index with [ ], exactly like a list.; Picture a shipping label already printed and sealed: a name and a date, side by side, in a fixed order.
Breaks
You mean a one-item tuple, but write plain brackets.; The count on the left does not match the tuple.
sound
These are stated as this lesson states them — each one survives the edge cases Session 15 - Tuples & Unpacking puts it through.
flawed
Each of these is lifted from a trap in this deck: reasonable-sounding, and wrong in a way that only shows up once you rely on it.

70. Tuples can be dictionary keys

Concept

Because a tuple never changes, Python can use it as a dict key - handy for keying on a pair, like a grid coordinate.

A list cannot be a key (it can change), but a tuple of the same values can.

71. A (row, col) coordinate as a key

Worked example

distances = {}
distances[(0, 0)] = 0
distances[(1, 2)] = 5
print(distances[(1, 2)])
print(distances)

Each key is a coordinate tuple

Why: The pair (1, 2) works as a single, unchangeable key.

Look one up by its tuple

Why: Verified by execution: distances[(1, 2)] is 5.

keyvalue
(0, 0)0
(1, 2)5
lookup (1, 2)5

72. Watch it run: A (row, col) coordinate as a key

Pattern

Step through it

Step through A (row, col) coordinate as a key one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: key is (0, 0)
  2. Step 2: key is (1, 2)
  3. Step 3: key is lookup (1, 2)

73. Tuple vs List

Section

Part 8

74. When to use each

Concept

Reach for a tuple when the group is a fixed record whose size and meaning do not change - a coordinate, a name-and-date, a function's several results.

Reach for a list when you will add, remove, or reorder items - a to-do list, a growing collection of scores.

75. Teach it back: When to use each

Explain it

Discussion prompt

Explain When to use each to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

Reach for a tuple when the group is a fixed record whose size and meaning do not change - a coordinate, a name-and-date, a function's several results.

76. Restore the missing line: Tuples support read-only operations

Fill the middle

Fill in the blanks

From Tuples support read-only operations — one line has had its right-hand side removed. Put it back.

t = (1, 2, 3)
print(len(t))
print(2 in t)
print(t + (4, 5))
print(t * 2)

Why: t is what everything below it consumes, so the wrong expression here fails later and somewhere else. These read or build new tuples; none of them change t.

77. Tuples support read-only operations

Worked example

t = (1, 2, 3)
print(len(t))
print(2 in t)
print(t + (4, 5))
print(t * 2)

len, in, +, and * all work

Why: These read or build new tuples; none of them change t.

Read the output

Why: Verified by execution: + and * return brand-new tuples, leaving t as (1, 2, 3).

expressionvalue
len(t)3
2 in tTrue
t + (4, 5)(1, 2, 3, 4, 5)
t * 2(1, 2, 3, 1, 2, 3)

78. Tuples still have count and index

Concept

Being immutable only blocks changing items. You can still ask read-only questions: .count(x) and .index(x).

count tells you how many times a value appears; index gives the position of its first appearance.

79. By analogy: Tuples still have count and index

Analogy

Discussion prompt

Explain Tuples still have count and index by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

Being immutable only blocks changing items. You can still ask read-only questions: .count(x) and .index(x).

80. count and index on a tuple

Worked example

votes = ("yes", "no", "yes", "yes")
print(votes.count("yes"))
print(votes.index("no"))

count tallies how many match

Why: Three of the four items are "yes".

index finds the first position

Why: Verified by execution: "no" first appears at index 1. Both read the tuple without changing it.

callvalue
votes.count("yes")3
votes.index("no")1

81. Draw the shape of it: count and index on a tuple

Blank canvas

Draw it

Draw what count and index on a tuple just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

82. Predict the next row: Tuples compare item by item

Pattern

Predict first

The table runs: (1, 2) == (1, 2) | True · (1, 2) < (1, 3) | True

In Tuples compare item by item, given the rows so far: what is the next one — the row where comparison is (1, 5) < (2, 0)?

Correct: (1, 5) < (2, 0) | True

comparisonvalue
(1, 2) == (1, 2)True
(1, 2) < (1, 3)True
(1, 5) < (2, 0)True

Why: The relationship between the columns, not the individual numbers, is what generates the next row. Two tuples are equal only when all their items match in order.

83. Tuples compare item by item

Worked example

print((1, 2) == (1, 2))
print((1, 2) < (1, 3))
print((1, 5) < (2, 0))

Equality checks every item

Why: Two tuples are equal only when all their items match in order.

Less-than compares left to right

Why: Python compares the first items; only if they tie does it look at the next. Verified by execution.

comparisonvalue
(1, 2) == (1, 2)True
(1, 2) < (1, 3)True
(1, 5) < (2, 0)True

84. Inspect it line by line: Tuples compare item by item

Error analysis

Annotate

Walk the callouts on Tuples compare item by item. Each one is a place this is easy to get subtly wrong.

  • Two tuples are equal only when all their items match in order.
  • Python compares the first items; only if they tie does it look at the next. Verified by execution.

85. The differences at a glance

Concept

Same indexing and looping; the split is whether the contents can change.

featuretuplelist
brackets( )[ ]
change items?no (immutable)yes (mutable)
can be a dict key?yesno
good forfixed recordsgrowing collections

86. Break it if you can: The differences at a glance

Counterexample

Discussion prompt

Same indexing and looping; the split is whether the contents can change.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

87. Patterns & Checks

Section

Part 9

88. Working with tuples

Pattern

1. Build with commas: t = (a, b) - and (x,) for one item

Why: The comma makes the tuple; a lone (x) is not one.

2. Unpack with matching names: a, b = t

Why: Left count must equal right count, or use *rest for the leftovers.

3. Return several values as one tuple: return x, y

Why: The caller unpacks it into names, or keeps the whole tuple.

4. Do not edit - rebuild if you must change it

Why: Tuples are immutable; slice and join a new one, or use a list.

89. Tuple or list?

Pattern

Fixed record, set size? Use a tuple

Why: Coordinates, name/date pairs, multiple return values - things that should not change.

Will grow or shrink? Use a list

Why: You need append, remove, or reorder.

Need it as a dict key? It must be a tuple

Why: Lists cannot be keys because they can change.

90. Where this shows up: Session 15 - Tuples & Unpacking

Real world

Discussion prompt

Outside this lesson: where does Session 15 - Tuples & Unpacking actually turn up? Name one concrete situation — a job, a piece of software someone ships, a decision somebody has to make — and say which part of Tuple or list? is doing the work in it.

Hint: Vague is the failure mode here. "Engineering" is not a situation; "deciding whether this build is fast enough to ship" is.

Answer:

Session 15 of the Python Fundamentals series, in depth. Tuples as immutable, ordered sequences: creating them with (a, b), the single-element trailing-comma rule, packing and unpacking, multiple assignment, one-line swapping, unpacking tuples in for loops, returning several values from a function, and star (*rest) unpacking.

91. Check: is it a tuple?

Check

Watch the comma.

x = (7)
print(type(x))
comma?type
no?

Check your understanding

What does this print?

  • A. <class 'int'> (correct)
  • B. <class 'tuple'>
  • C. (7,)
  • D. <class 'list'>

Answer: A

Why: Without a trailing comma, (7) is just the number 7 in brackets, so its type is int. A tuple would need (7,). Verified by execution.

Why B tempts people
A one-item tuple needs the comma: (7,). Plain (7) is only grouping brackets.
Why C tempts people
That is the value of a one-item tuple, but type() prints the class, and here x is not a tuple anyway.
Why D tempts people
Square brackets make a list; these are round grouping brackets around a single int.

92. Check: the swap

Check

Trace both assignments.

a, b = 2, 9
a, b = b, a
print(a, b)
stepab
start29
after swap??

Check your understanding

What does this print?

  • A. 9 2 (correct)
  • B. 2 9
  • C. 9 9
  • D. 2 2

Answer: A

Why: The right side packs the current values (9, 2) first, then unpacks them into a, b - so a becomes 9 and b becomes 2. Verified by execution.

Why B tempts people
That is the starting order; the swap line flips them before printing.
Why C tempts people
a is not copied into b twice - Python packs (b, a) as (9, 2) before assigning, so b keeps a distinct value.
Why D tempts people
b does not overwrite a first; the whole right side is evaluated before either name changes.

93. Check: unpack in a loop

Check

What prints on the second pass?

pairs = [(1, "one"), (2, "two")]
for n, word in pairs:
    print(n, word)
passnword
11one
2??

Check your understanding

What is the SECOND line of output?

  • A. 2 two (correct)
  • B. 1 one
  • C. (2, 'two')
  • D. 2 one

Answer: A

Why: On the second pass the loop hands over (2, 'two'), and n, word unpacks it to n=2 and word='two', printing 2 two. Verified by execution.

Why B tempts people
That is the first pass. The question asks for the second line, which uses the second tuple.
Why C tempts people
Because the for line unpacks into n and word, you print the two items with a space, not the whole tuple.
Why D tempts people
word comes from the same tuple as n, so it is 'two', not 'one' from the previous pass.

94. What each one costs: Check: unpack in a loop

Trade off

Comparison matrix

From Check: unpack in a loop: every row here is a choice with a cost. Fill the word column, then say which row you would actually pick and what you give up for it.

passnword
11one
2??

95. Check: star unpacking

Check

Where does the star's value land?

first, *rest = [1, 2, 3, 4]
print(rest)
namevalue
first1
rest?

Check your understanding

What does print(rest) show?

  • A. [2, 3, 4] (correct)
  • B. (2, 3, 4)
  • C. 2
  • D. [1, 2, 3, 4]

Answer: A

Why: first takes 1, and *rest collects the remaining items into a list, so rest is [2, 3, 4]. A starred target always produces a list. Verified by execution.

Why B tempts people
A starred target collects into a list, not a tuple, even when the right side is a tuple.
Why C tempts people
rest gathers all leftover items, not just the next single one.
Why D tempts people
first has already taken the leading 1, so it is not part of rest.

96. Fill in: value for Check: star unpacking

Comparison

Comparison matrix

From Check: star unpacking: refill the value column from what you know. The rest of the table is as it appeared.

namevalue
first1
rest?

97. Check: changing a tuple

Check

Can you assign into it?

t = (1, 2, 3)
t[0] = 99
actionresult
t[0] = 99?

Check your understanding

What happens?

  • A. TypeError: 'tuple' object does not support item assignment (correct)
  • B. t becomes (99, 2, 3)
  • C. t becomes [99, 2, 3]
  • D. IndexError: tuple index out of range

Answer: A

Why: Tuples are immutable, so assigning to t[0] raises TypeError: 'tuple' object does not support item assignment. The tuple is never changed. Verified by execution.

Why B tempts people
Immutability blocks the assignment - the item is never replaced, so t stays (1, 2, 3).
Why C tempts people
A tuple never turns into a list from an assignment; the operation just fails.
Why D tempts people
Index 0 is valid; the error is about assignment being disallowed, not a bad index.

98. Check: returning several values

Check

What comes back, and in what form?

def min_max(nums):
    return min(nums), max(nums)

print(min_max([4, 9, 1, 7]))
minmaxreturns
19?

Check your understanding

What does this print?

  • A. (1, 9) (correct)
  • B. 1 9
  • C. [1, 9]
  • D. 1

Answer: A

Why: return min(nums), max(nums) packs the two results into one tuple, so printing the call shows (1, 9). Verified by execution.

Why B tempts people
Printing the returned tuple shows it with brackets and a comma; 1 9 would need the values unpacked into two names first.
Why C tempts people
The comma builds a tuple, not a list - a list would need square brackets.
Why D tempts people
return sends back both values as one tuple, not just the minimum.

99. Connect it up: Session 15 - Tuples & Unpacking

Connect it up

Draw it

One page, no notation unless you need it: draw how these connect — What a Tuple Is · Packing & Unpacking · The One-Line Swap · Unpacking in Loops · Returning Many Values · Star Unpacking. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.

100. What you can do now

Recap

A tuple is an ordered, immutable group. The comma builds it, unpacking spreads it across names, and immutability makes it a safe fixed record and a valid dict key.

You writeIt means
(3, 4)a two-item tuple
(5,)a one-item tuple (comma required)
a, b = b, aswap in one line
for name, score in pairs:unpack each tuple in the loop
return x, yhand back several values as one tuple
first, *rest = seqfirst item, then the rest as a list

Use tuples for fixed records, lists for things that change. Next session we go deeper into sets - unordered collections with no duplicates.

Sources

  1. Python 3 Tutorial - Tuples and Sequences
  2. Python 3 Reference - Assignment statements (unpacking, starred targets)
  3. Python 3 Standard Types - Tuples
  4. All snippets and error messages executed and copied from CPython 3.12. — Author verification run, 2026-07-15 (Python Fundamentals series, Session 15).

Want this taught 1-on-1? Alexander tutors Python Fundamentals — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108