PythonMastery
reference 5 min read · lesson 6 of 25 in Reference

Python Tuple Cheat Sheet

1 · The lesson

read

A tuple is an ordered group of values, like a list, but you cannot change it after you create it. Use a tuple for a small, fixed record, such as a point (3, 4) or a name and an age. Because a tuple cannot change, it can be a dictionary key or a set member. A list cannot be either. For the full tutorial, see Tuples.


1. Create a tuple

The comma makes the tuple, not the brackets. A tuple with one item needs a comma after the item.

python
1, 2                 # (1, 2)
(42,)                # (42,)  (one item: the comma is required)
(42)                 # 42  (no comma, so this is just the number 42)
()                   # ()  (an empty tuple)
tuple("abc")         # ('a', 'b', 'c')  (anything you can loop over becomes a tuple)
tuple([1, 2])        # (1, 2)  (a list turned into a tuple)
tuple(range(3))      # (0, 1, 2)

2. Read items

Indexing and slicing work exactly as they do for lists. A tuple has only two methods: count() and index().

python
t = (10, 20, 30, 40)
t[0]                     # 10  (the first item)
t[-1]                    # 40  (the last item)
t[1:3]                   # (20, 30)  (a slice of a tuple is a tuple too)
t[::-1]                  # (40, 30, 20, 10)
len(t)                   # 4
30 in t                  # True
t.count(20)              # 1
t.index(30)              # 2
min(t), max(t), sum(t)   # (10, 40, 100)

3. Build a new tuple

You cannot change a tuple, but you can build a new one from parts of the old one. If you need to make many changes, turn it into a list first.

python
(1, 2) + (3,)               # (1, 2, 3)  (+ joins two tuples into a new tuple)
(0,) * 3                    # (0, 0, 0)
t[:1] + (99,) + t[2:]       # (10, 99, 30, 40)  (a new tuple with the second item replaced)
list(t)                     # [10, 20, 30, 40]
sorted((3, 1, 2))           # [1, 2, 3]  (sorted() always returns a list)
tuple(sorted((3, 1, 2)))    # (1, 2, 3)
+ setup added so this can run · re-runs 1 earlier block on this page first
t = ["alpha", "beta", "gamma"]

# Earlier blocks on this page that this one builds on, re-run quietly first.
_pm_earlier = [
    't = (10, 20, 30, 40)\nt[0]                     # 10  (the first item)\nt[-1]                    # 40  (the last item)\nt[1:3]                   # (20, 30)  (a slice of a tuple is a tuple too)\nt[::-1]                  # (40, 30, 20, 10)\nlen(t)                   # 4\n30 in t                  # True\nt.count(20)              # 1\nt.index(30)              # 2\nmin(t), max(t), sum(t)   # (10, 40, 100)',
]
def _pm_run_earlier(_srcs, _g):
    import sys as _s, io as _io, warnings as _w
    for _src in _srcs:
        _o, _e = _s.stdout, _s.stderr
        _s.stdout = _s.stderr = _io.StringIO()
        try:
            with _w.catch_warnings():
                _w.simplefilter('ignore')
                exec(compile(_src, '<earlier block>', 'exec'), _g)
        except (Exception, SystemExit):
            pass
        finally:
            _s.stdout, _s.stderr = _o, _e
    if 'matplotlib.pyplot' in _s.modules:
        _s.modules['matplotlib.pyplot'].close('all')   # their plots belong to their own blocks
_pm_run_earlier(_pm_earlier, globals())
del _pm_earlier, _pm_run_earlier

4. Compare tuples

Python compares tuples item by item, from left to right. The first pair of items that differ decides the result. This is why sorting a list of tuples sorts by the first item, then by the second item when the first items are equal.

python
(1, 2) == (1, 2)               # True
(1, 9) < (2, 0)                # True  (1 is smaller than 2, so the rest does not matter)
(1, 2) < (1, 2, 0)             # True  (a shorter tuple that matches the start comes first)
max([("b", 2), ("a", 9)])      # ('b', 2)

5. Unpack a tuple

Unpacking puts each item of a tuple into its own variable, in one line. A name with * collects all the remaining items into a list. Use _ as the name for an item you do not need.

python
x, y = (3, 4)
y                                  # 4
first, *rest = (1, 2, 3, 4)
rest                               # [2, 3, 4]
*init, last = (1, 2, 3, 4)
init                               # [1, 2, 3]
name, _, age = ("Ada", "London", 36)
age                                # 36
(a, b), c = (1, 2), 3              # a tuple inside a tuple unpacks the same way
b                                  # 2
a, b = 1, 2
a, b = b, a                        # swap two values without a temporary variable
a                                  # 2

enumerate() gives (index, item) tuples, and the for loop unpacks each tuple:

python
for i, ch in enumerate("ab"):
    print(i, ch)
python
0 a
1 b

6. Tuples and functions

When a function returns several values separated by commas, it returns one tuple. A * in front of a parameter name collects any extra arguments into a tuple.

python
def min_max(xs):
    return min(xs), max(xs)

lo, hi = min_max([3, 1, 2])
hi                                 # 3
divmod(17, 5)                      # (3, 2)  (built-in functions return tuples too)
list(zip("ab", (1, 2)))            # [('a', 1), ('b', 2)]
list({"a": 1}.items())             # [('a', 1)]  (dictionary items are (key, value) tuples)
pow(*(2, 10))                      # 1024  (* passes each item as a separate argument)

def total(*nums):                  # nums is a tuple of all the arguments
    return sum(nums)

total(1, 2, 3)                     # 6
+ setup added so this can run · defines nums
# Lightweight mock for objects whose attributes/methods aren't critical
class _AutoMock:
    def __init__(self, name='mock'): self._name = name
    def __getattr__(self, k): return _AutoMock(self._name + '.' + k)
    def __call__(self, *a, **kw):
        print('-> ' + self._name + '() called')
        return _AutoMock(self._name + '()')
    def __repr__(self): return '<mock ' + self._name + '>'
    def __str__(self): return '<mock ' + self._name + '>'
    def __bool__(self): return True
    def __iter__(self): return iter([])
    def __len__(self): return 0
    def __getitem__(self, k): return _AutoMock(self._name + '[...]')
    def __setitem__(self, k, v): pass
    def __enter__(self): return self
    def __exit__(self, *a): return False
    async def __aenter__(self): return self
    async def __aexit__(self, *a): return False
    def __add__(self, o): return self
    def __radd__(self, o): return self
    def __sub__(self, o): return self
    def __mul__(self, o): return self
    def __rmul__(self, o): return self
    def __truediv__(self, o): return self
    def __eq__(self, o): return isinstance(o, _AutoMock)
    def __hash__(self): return hash(self._name)
    def __lt__(self, o): return True
    def __le__(self, o): return True
    def __gt__(self, o): return False
    def __ge__(self, o): return False
    def __mro_entries__(self, bases): return (object,)

nums = _AutoMock('nums')

7. Tuples as dictionary keys and set members

A value can be a dictionary key or a set member only if it is hashable: Python can compute a fixed number from it, which needs a value that never changes. A tuple is hashable when every item inside it is hashable. A list is never hashable.

python
dist = {("Paris", "Rome"): 1106}
dist[("Paris", "Rome")]            # 1106
len({(0, 0), (0, 0), (1, 2)})      # 2  (a set of grid points; the duplicate is dropped)
tuple(sorted(["b", "a"]))          # ('a', 'b')  (turn a list into a tuple to use it as a key)

{[1, 2]: "x"} raises TypeError: unhashable type: 'list' (full error page).

8. namedtuple

A namedtuple is a tuple whose items also have names, so p.x is easier to read than p[0].

python
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
p                      # Point(x=3, y=4)
p.x                    # 3  (reads an item by its name)
p[1]                   # 4  (or by its index)
p._replace(x=0)        # Point(x=0, y=4)  (a new tuple with a new x)
p._asdict()            # {'x': 3, 'y': 4}
p == (3, 4)            # True  (it is still a normal tuple)
Point._fields          # ('x', 'y')

9. typing.NamedTuple

typing.NamedTuple does the same job, but you write it as a class. A class lets you add types, default values and methods.

python
from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int = 0          # a default value

    def length(self) -> float:
        return (self.x ** 2 + self.y ** 2) ** 0.5

Point(5)                # Point(x=5, y=0)
Point(3, 4).length()    # 5.0

See Type hints and Collections.

10. Tuple or list?

TupleList
Can it change?NoYes
Can it be a dict key?Yes, if its items are hashableNo
Written as(1, 2)[1, 2]
Methods2 (count, index)11
Good forA fixed record where each position means something: (x, y)A collection of the same kind of thing that grows: scores

Common mistakes

Forgetting the comma in a one-item tuple. ("a") is just the string 'a'. Write ("a",).

A stray comma. A comma at the end of a line makes a tuple, even without brackets:

python
x = 1,
x           # (1,)

Changing an item. t[0] = 99 raises TypeError: 'tuple' object does not support item assignment. Build a new tuple, or use a list.

Calling list methods. t.append(50) raises AttributeError: 'tuple' object has no attribute 'append'. Write t = t + (50,).

Unpacking the wrong number of items. a, b = (1, 2, 3) raises ValueError: too many values to unpack (full error page). Use a, b, *_ = (1, 2, 3) to ignore the extra items.

Expecting a list inside a tuple to stay fixed. The tuple cannot change which objects it holds, but a list inside it can still change:

python
u = ([1], 2)
u[0].append(9)
u           # ([1, 9], 2)

Passing a string to tuple(). tuple("hi") splits the string into characters:

python
tuple("hi")     # ('h', 'i')
("hi",)         # ('hi',)

Comparing a tuple with a list. (1, 2) == [1, 2] is False. A tuple is never equal to a list, even with the same items.

See also

Found this useful? Share it with a friend who’s learning Python.