CollectionsChapter 35 of 114
Tuples
An ordered sequence that cannot change, and why that is useful.
Round brackets, or none at all
point = (4, 9)
also_a_tuple = 4, 9
print(point, type(point))
print(also_a_tuple)Output
(4, 9) <class 'tuple'> (4, 9)
It is the commas that make a tuple. The brackets only group, which is why returning several values from a function gives you a tuple without any brackets in sight.
The one-item trap
one = (5,)
not_a_tuple = (5)
print(type(one), type(not_a_tuple))Output
<class 'tuple'> <class 'int'>
An empty tuple is the exception — () works, because there is nothing to be ambiguous about.
It cannot change
point = (4, 9)
try:
point[0] = 1
except TypeError as problem:
print("TypeError:", problem)Output
TypeError: 'tuple' object does not support item assignment
Everything that reads a tuple works exactly as it does for a list: indexing, slicing, len(), in, looping, unpacking.
point = (4, 9, 16)
print(point[0], point[-1], point[1:])
print(len(point), 9 in point)Output
4 16 (9, 16) 3 True
Only two methods exist, because the rest would change it:
values = (1, 2, 2, 3)
print(values.count(2), values.index(3))Output
2 3
Immutable is not the same as unchangeable inside
A tuple fixes which objects it holds. If one of those objects is a list, that list can still change:
row = ("Ada", [1, 2])
row[1].append(3)
print(row)Output
('Ada', [1, 2, 3])Why bother
- It says the shape is fixed. A coordinate has two numbers, always.
- It can be a dictionary key, which a list cannot, because it hashes.
- It is slightly smaller and faster, which occasionally matters.
locations = {(0, 0): "origin", (1, 2): "somewhere"}
print(locations[(0, 0)])
try:
{[0, 0]: "nope"}
except TypeError:
print("a list cannot be a key")Output
origin a list cannot be a key
Unpacking
Tuples make multiple return values read well:
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 1, 4])
print(low, high)Output
1 4
Named tuples, when positions get confusing
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(4, 9)
print(p.x, p.y)
print(p[0], tuple(p))Output
4 9 4 (4, 9)
It is still a tuple in every way, with names attached. For anything richer, a dataclass is usually the better tool.
Test yourself
3 questionsWhat is type((5))?
Show the answer
int — It is five in brackets. A one-item tuple needs the trailing comma: (5,).
Why can a tuple be a dictionary key when a list cannot?
Show the answer
A tuple is hashable because it cannot change — A key's hash must not change while it is in the dictionary, so mutable objects are refused.
Can anything about ('Ada', [1, 2]) change?
Show the answer
Yes, the list inside can be changed — A tuple fixes which objects it holds, not what those objects contain.
Sets
An unordered collection with no duplicates, and fast membership tests.