Skip to content
aviral gupta

// 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.

Lesson 3 of 6 in B4 Data structures

You will be able to

  • Pack values into tuples and unpack them into names: in assignments, swaps and for loops
  • Write empty and one-element tuples correctly
  • Explain what a tuple’s immutability forbids and what it still allows
  1. Warm-up · Activity 1 of 7

    Warm-up from lesson B4.2: which comprehensions give [(0, 0), (1, 1), (2, 4)]? Pick all that apply.

    Select all that apply.

  2. 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)
  3. Practice · Activity 3 of 7

    Fill in one character so that single is a tuple with one item.

    single = ("hello"____)
    single = ("hello")
  4. 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)
  5. Practice · Activity 5 of 7

    Match each expression to its value.

  6. 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)
  7. 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.py

Output

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
  1. Hint 1

    Square brackets always build a list.

  2. Hint 2

    Values separated by commas after return are packed into a tuple.

  3. 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.py

Run the checks (needs learnrun.py in the same folder):

python learnrun.py test
Download learnrun.py

Exercise 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
  1. Hint 1

    Tuples compare item by item: (-30, "ben") comes before (-21, "cleo"). A minus sign puts high points first.

  2. Hint 2

    sorted(scores, key=lambda pair: (-pair[1], pair[0])) sorts by points, then by name, and leaves scores alone.

  3. 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.py

Run the checks (needs learnrun.py in the same folder):

python learnrun.py test
Download learnrun.py

Common mistakes

Changing an item of a tuple

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

What Python prints

TypeError: 'tuple' object does not support item assignment

Why, 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.

Report a problem

Spotted something wrong or unclear? Say what, and it will be checked and fixed.

#

At least 20 characters.

Only if you want a reply.

Key ideas

The comma makes the tuple

A tuple is a fixed sequence of values: t = 12, 34, "x" packs three values into one tuple. Python prints tuples in parentheses, and you often need them in your code too, for example inside a function call, but it is the comma that creates the tuple. So (5) is just the number 5, while (5,) and 5, are tuples with one item. An empty tuple is (). Tuples support indexing, slicing, len(), + and *, like lists.

Unpacking

x, y = point unpacks a sequence into names; the number of names must match the number of items, or Python raises ValueError. It works with any sequence: a, b, c = "xyz". a, b = b, a swaps two variables, because the right side is packed into a tuple before anything is assigned. A function returns several values by returning a tuple, and the caller unpacks it: lowest, highest = min_max(nums). for name, score in pairs: unpacks each pair in turn.

Immutable, with limits

You cannot change a tuple: t[0] = 9 raises TypeError, and tuples have no append or remove. You can build a new tuple, t + (4,), and bind a name to it. A tuple can hold mutable objects, such as a list, and that list can still change: the tuple keeps referring to the same list. Use a tuple for a fixed group of related values, such as a point or a date, and a list for a collection that grows.

Sources

Last reviewed September 29, 2026