Tuples and unpacking

Beginner30 min

Group values in immutable tuples, pull them apart by unpacking, and collect leftovers with star syntax.

What you will learn
  • Create tuples, including the one-item case
  • Explain what immutability does and does not protect
  • Unpack tuples and lists into names, including with a starred name
  • Spot the several-values-at-once idiom behind divmod, swapping and enumerate
On this page

A list says “a changeable pile of things”. Sometimes you want the opposite: a small, fixed bundle, such as an (x, y) point or a (name, year) pair. That is a tuple. Tuples also power one of Python’s nicest habits, unpacking, which lets you pull a bundle apart into named pieces in a single line.

Tuples

tuple_basics.py
point = (3, 4)
print(point[0], point[1], len(point))
Output
3 4 2

A tuple is an ordered sequence like a list, with indexing, slicing, len and in. The difference is that it is immutable: once built, you cannot assign to an index, append or remove.

point = (3, 4)
point[0] = 10
Output
TypeError: 'tuple' object does not support item assignment

Use a tuple when the group is a single fixed thing, and a list when it is a collection that will grow or shrink.

It is the comma that makes a tuple, not the parentheses. That is why (5,) is a one-item tuple while (5) is just the number 5 in brackets.

tuple_comma.py
single = (5,)
not_a_tuple = (5)
print(type(single).__name__, type(not_a_tuple).__name__)
pair = 1, 2
print(pair)
Output
tuple int
(1, 2)

The parentheses are only needed to avoid ambiguity, so pair = 1, 2 builds a tuple without them. You have already seen this in the variables lesson, where a, b = b, a swapped two names, and in divmod(17, 5), which returns the pair (3, 2).

Immutability protects the tuple’s own slots, not whatever those slots refer to. A tuple that contains a list still lets you change that list. And because a tuple of immutable things can never change, it is hashable, so it can be a dictionary key or a set member, as the next lessons show.

Unpacking

x, y = point is unpacking: the names on the left receive the items on the right, in order. It works with any iterable, not only tuples.

unpack_basic.py
point = (3, 4)
x, y = point
print(x, y)
quotient, remainder = divmod(17, 5)
print(quotient, remainder)
low, high = min(4, 9, 2), max(4, 9, 2)
print(low, high)
Output
3 4
3 2
2 9

The number of names must match the number of items, otherwise Python raises ValueError:

p, q = [1, 2, 3]
Output
ValueError: too many values to unpack (expected 2, got 3)

Two everyday idioms fall out of this. a, b = b, a swaps two names without a temporary variable: the right side is fully built as a tuple before any assignment happens. And a function can “return several values” by returning a tuple, which the caller unpacks, as divmod does. Strictly, such a function returns one tuple. Unpacking just makes it feel like two values. You will write your own functions like this in the functions module.

Star unpacking

Put a * in front of one name and it soaks up whatever the other names do not take. The starred name is always a list, even when the source is a string or a range, and it is an empty list when nothing is left over. Only one starred name is allowed per pattern.

star_unpacking.py
first, *rest = [10, 20, 30, 40]
print(first, rest)
*init, last = "abcd"
print(init, last)
head, *middle, tail = range(1, 6)
print(head, middle, tail)
only, *none = [7]
print(only, none)
Output
10 [20, 30, 40]
['a', 'b', 'c'] d
1 [2, 3, 4] 5
7 []

Unpacking in a loop and in nested patterns

You have already used unpacking without noticing: for position, letter in enumerate(...) unpacks each pair as the loop goes round. It works for any list of pairs:

unpack_in_loop.py
pairs = [("Ada", 1815), ("Alan", 1912)]
for name, year in pairs:
print(name, year)
Output
Ada 1815
Alan 1912

Patterns can nest, with parentheses mirroring the shape of the data:

unpack_nested.py
(a, b), c = (1, 2), 3
print(a, b, c)
Output
1 2 3

Spreading a list with *

The same star also works in the other direction. In a call, print(*numbers) spreads a list into separate arguments, and [0, *numbers, 4] splices one into a new list.

star_spread.py
numbers = [1, 2, 3]
print(*numbers)
combined = [0, *numbers, 4]
print(combined)
Output
1 2 3
[0, 1, 2, 3, 4]

Common pitfalls

  • Forgetting the comma in a one-item tuple. (5) is an int. Write (5,).
  • Expecting a tuple to be deeply frozen. ([1], 2) still lets you change the inner list. Immutability is one level deep.
  • Mismatched counts. p, q = [1, 2, 3] raises ValueError. Add a starred name if the length varies.
  • Treating the starred name as a tuple. It is a list, whatever the source was.
  • Using a tuple of mutable items as a dict key. ([1], 2) as a key raises TypeError, because the list inside makes the whole tuple unhashable.
ExerciseParse a coordinate

Turn the text "3,4" into the tuple (3, 4) of two integers, and print it. Use split(","), unpack the two pieces, and convert each with int.

Input: text = "3,4", then try " 10, -2 ". Expected output: (3, 4) for the first and (10, -2) for the second, because int ignores the spaces around a number. The file shows the first.

Show solution
parse_coords.py
text = "3,4"
x_text, y_text = text.split(",")
print((int(x_text), int(y_text)))
Output
(3, 4)

Unpacking the result of split also checks the length for us. With the text "1,2,3" the unpacking raises ValueError: too many values to unpack (expected 2, got 3).

ExerciseSummary statistics

Given numbers = [4, 8, 15, 16, 23, 42], unpack the minimum, maximum and mean into three names low, high and mean in one assignment, and print them with the mean rounded to 2 decimals. Then use star unpacking to split ["Ada", "Ben", "Cy"] into a winner and the others, and print them.

Input: none. Expected output: 4 42 18.0 then Ada ['Ben', 'Cy'].

Show solution
stats_tuple.py
numbers = [4, 8, 15, 16, 23, 42]
low, high, mean = min(numbers), max(numbers), sum(numbers) / len(numbers)
print(low, high, round(mean, 2))
winner, *others = ["Ada", "Ben", "Cy"]
print(winner, others)
Output
4 42 18.0
Ada ['Ben', 'Cy']

The right side builds one tuple of three values, and the left side unpacks it in a single assignment.

Summary

  • A tuple is an ordered, immutable sequence. The comma builds it, so a one-item tuple needs a trailing comma.
  • Unpacking assigns items to names in one line: x, y = point, a, b = b, a, and *rest collects the leftovers into a list.
  • Several values “returned together”, as from divmod, are really one tuple.

Next: dictionaries.