13 · Tuples: immutable, hashable, often returned
Unpacking, the one-element gotcha, extended unpacking with *, and namedtuple for readable record types.
A tuple is an **immutable** sequence — once created, it cannot change. That immutability makes tuples safe as dict keys, safe to share between functions, and the natural container for a function's multiple return values.
Without this:
Without tuples, returning multiple values from a function (e.g. `loss, accuracy`) would require a dict or a class — more ceremony for what is conceptually a record.
Tuple literals use parentheses: (1, 2, 3). Parentheses are actually optional — 1, 2, 3 is also a tuple — but including them is idiomatic for clarity. Tuples support the same indexing and slicing as lists but do not support item assignment. They are also hashable, so they can be used as dict keys or placed inside sets.
Python (in browser)
The swap `a, b = b, a` works because the right-hand side is evaluated *first* as the tuple `(b, a)`, then unpacked. No temporary variable needed.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
The starred name `*rest` absorbs all remaining elements into a **list**. You can place it at the start, middle, or end of the unpacking target.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`namedtuple` is a zero-overhead way to add attribute names to a tuple. The result is still immutable and iterable — perfect for structured return values.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
What is `type((1))` in Python?
A 2-tuple `(x, y)` is a point in R² — exactly what MML chapter 2 defines as a vector in two-dimensional space. Python's tuples make that mathematical concept directly expressible in code.
- Tuples are immutable sequences — same indexing as lists, but no item assignment. Hashable: usable as dict keys.
- `a, b = b, a` is a Pythonic swap — no temp variable. `first, *rest = t` captures the tail into a list.
- `(1,)` is a one-element tuple; `(1)` is just the integer `1`. The trailing comma is mandatory.
Functions in ML frameworks routinely return tuples: `return loss, accuracy` in a training step; `(input, target)` pairs in PyTorch DataLoaders; `model.evaluate()` in Keras returns `(loss, metric)`. Shape descriptors like `(batch_size, sequence_length, hidden_dim)` are tuples because they are fixed records, not mutable collections.
If you remove it: Without tuples, every multi-value return requires a dict or a dataclass — more ceremony. Without immutability, shape descriptors could accidentally be mutated mid-pipeline, causing cryptic dimension-mismatch errors.