Warm-up · Activity 1 of 7
// B4.3 · ~25 min · Beginner
Tuples and unpacking
After this lesson you can pack values into a tuple and unpack them into names, write empty and one-element tuples, and predict what a tuple lets you change.
Predict · Activity 2 of 7
Predict before you read on: what does this print?
a, b = 1, 2 a, b = b, a print(a, b)Practice · Activity 3 of 7
Fill in one character so that single is a tuple with one item.
single = ("hello"____)single = ("hello")Practice · Activity 4 of 7
The loop unpacks each pair. What does this print?
pairs = [("ana", 3), ("ben", 5)] total = 0 for name, score in pairs: total += score print(name, total)Practice · Activity 5 of 7
Match each expression to its value.
Brain teaser · Activity 6 of 7
Brain teaser. Both targets are assigned in one statement. What does this print?
x = [0, 1] i = 0 i, x[i] = 1, 2 print(x)Apply · Activity 7 of 7
Mini-task. Write min_max(nums), which walks the list once and returns the smallest and the largest value as a tuple. Call it with lo, hi = min_max([4, -2, 9, 0]) and print both. What does min_max([7]) return?
Check your work against this list
Build it yourself
Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.
Worked example
A route of points
A route is a list of (x, y) points. Each point is a tuple, because its two values belong together and never change. bounding_box() returns four values as one tuple, and the caller unpacks them into four names. The for loop unpacks each point, and one line swaps the start and the end. At the end the list gets a new first point: the list changes, the old tuple does not. Add a point and run it again.
main.py
# Each point is a fixed (x, y) pair, so a tuple fits.
route = [(0, 0), (3, 4), (3, 0)]
def bounding_box(points):
"""Return the smallest and largest x and y as one tuple."""
xs = [x for x, y in points]
ys = [y for x, y in points]
return min(xs), min(ys), max(xs), max(ys)
left, bottom, right, top = bounding_box(route)
print("Box:", left, bottom, right, top)
for x, y in route:
print("Point", x, y)
start, end = route[0], route[-1]
start, end = end, start
print("Swapped ends:", start, end)
origin = route[0]
route[0] = (1, 1) # the list can change: it now holds a different tuple
print("Route:", route, "origin:", origin)
Run it with
python main.pyOutput
Box: 0 0 3 4
Point 0 0
Point 3 4
Point 3 0
Swapped ends: (3, 0) (0, 0)
Route: [(1, 1), (3, 4), (3, 0)] origin: (0, 0)- return min(xs), min(ys), max(xs), max(ys) packs four values into one tuple.
- start, end = end, start swaps two tuples without a temporary variable.
- origin still refers to the old point (0, 0): replacing a list item does not change the tuple.
Change it and run it
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Exercises
Exercise 1 of 2
Three numbers at once
stats(nums) should return the lowest value, the highest value and the mean, as one tuple, so that a caller can write lowest, highest, mean = stats(nums). The starter returns a list instead. Make it return a tuple.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Hints
Hint 1
Square brackets always build a list.
Hint 2
Values separated by commas after return are packed into a tuple.
Hint 3
return min(nums), max(nums), sum(nums) / len(nums)
Show a solution
One way to solve it. Yours can look different and still pass the checks.
def stats(nums: list[float]) -> tuple[float, float, float]:
"""Return the lowest value, the highest value and the mean, as one tuple."""
return min(nums), max(nums), sum(nums) / len(nums)
Run it on your computer
Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.py
def stats(nums: list[float]) -> tuple[float, float, float]:
"""Return the lowest value, the highest value and the mean, as one tuple."""
return [min(nums), max(nums), sum(nums) / len(nums)]
test_main.py
from main import stats
def test_values():
"""Gives the lowest, the highest and the mean, in that order"""
lowest, highest, mean = stats([2, 8, 5])
assert (lowest, highest, mean) == (2, 8, 5.0), f"stats([2, 8, 5]) gave {(lowest, highest, mean)!r}, expected (2, 8, 5.0)"
def test_returns_tuple():
"""Returns a tuple, not a list"""
got = stats([2, 8, 5])
assert type(got) is tuple, f"stats returned a {type(got).__name__}, expected a tuple"
def test_single_value():
"""One value is the lowest, the highest and the mean"""
got = stats([4])
assert got == (4, 4, 4.0), f"stats([4]) returned {got!r}, expected (4, 4, 4.0)"
On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.
Run the program:
python main.pyRun the checks (needs learnrun.py in the same folder):
python learnrun.py testDownload learnrun.pyExercise 2 of 2
A leaderboard
leaderboard(scores) gets (name, points) pairs and should return lines such as "ben: 30", highest points first; equal points go in alphabetical order. The starter keeps the input order and indexes each pair. Sort with a key that returns a tuple, and unpack each pair into name and points.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Hints
Hint 1
Tuples compare item by item: (-30, "ben") comes before (-21, "cleo"). A minus sign puts high points first.
Hint 2
sorted(scores, key=lambda pair: (-pair[1], pair[0])) sorts by points, then by name, and leaves scores alone.
Hint 3
Then: [name + ": " + str(points) for name, points in ranked]
Show a solution
One way to solve it. Yours can look different and still pass the checks.
def leaderboard(scores: list[tuple[str, int]]) -> list[str]:
"""Return "name: points" lines, highest points first, ties by name."""
ranked = sorted(scores, key=lambda pair: (-pair[1], pair[0]))
return [name + ": " + str(points) for name, points in ranked]
Run it on your computer
Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.py
def leaderboard(scores: list[tuple[str, int]]) -> list[str]:
"""Return "name: points" lines, highest points first, ties by name."""
return [pair[0] + ": " + str(pair[1]) for pair in scores]
test_main.py
from main import leaderboard
def test_highest_first():
"""Puts the highest score first"""
got = leaderboard([("ana", 12), ("ben", 30), ("cleo", 21)])
assert got == ["ben: 30", "cleo: 21", "ana: 12"], f"got {got!r}, expected ['ben: 30', 'cleo: 21', 'ana: 12']"
def test_ties_by_name():
"""Equal scores are listed in alphabetical order"""
got = leaderboard([("zoe", 5), ("adam", 5), ("mia", 9)])
assert got == ["mia: 9", "adam: 5", "zoe: 5"], f"got {got!r}, expected ['mia: 9', 'adam: 5', 'zoe: 5']"
def test_input_unchanged():
"""Leaves the caller's list as it was"""
scores = [("ana", 1), ("ben", 2)]
leaderboard(scores)
assert scores == [("ana", 1), ("ben", 2)], f"the caller's list became {scores!r}"
On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.
Run the program:
python main.pyRun the checks (needs learnrun.py in the same folder):
python learnrun.py testDownload learnrun.pyCommon mistakes
Changing an item of a tuple
point = (3, 4)
point[0] = 5
What Python prints
TypeError: 'tuple' object does not support item assignmentWhy, and the fix
Tuples are immutable. Build a new tuple and bind the name to it: point = (5, point[1]). If the values really need to change one by one, a list is the better choice.
Unpacking into the wrong number of names
x, y = (1, 2, 3)
What Python prints
ValueError: too many values to unpack (expected 2, got 3)Why, and the fix
Unpacking needs one name per item. The message says how many it expected and how many it got. Add a name, x, y, z = …, or unpack a slice: x, y = values[:2].
Parentheses without a comma
size = (5)
print(len(size))
What Python prints
TypeError: object of type 'int' has no len()Why, and the fix
Parentheses alone only group: (5) is the integer 5. The comma makes the tuple, so write size = (5,) or size = 5, for a tuple with one item.
Python in the browser: Pyodide 314.0.7, MPL-2.0. Licence and source
Exit ticket
5 questions, no hints. Score 80% or more to complete the lesson.
Finish every activity above to unlock the exit ticket.