Guide Python Intermediate

11.8 Nested Tuples

Creating and accessing nested tuples with chained indices, and why a tuple's immutability is shallow, not deep -- a mutable object held in one of its slots, like a list, can still be freely modified.

2 min read

Creating and Accessing

>>> nested = ((1, 2, 3), (4, 5, 6))
>>> nested[1][2]
6

Updating Nested Mutable Objects

A tuple’s immutability only applies to its own slots — if one of those slots holds a mutable object (like a list), that inner object can still be freely modified. The tuple itself never changes (it still references the same list object); only the list’s own contents change.

flowchart LR T["tuple (immutable container)"] --> S0["t[0] = 1"] T --> S1["t[1] = 2"] T --> S2["t[2] -> list"] S2 --> L["[3, 4] (mutable)"]

t[2].append(99) is allowed — it mutates the inner list. t[2] = [9, 9] is not — it would rebind a tuple slot.

>>> t = (1, 2, [3, 4])
>>> t[2].append(99)      # ALLOWED -- mutates the inner list, not the tuple
>>> t
(1, 2, [3, 4, 99])
>>> t[2] = [1]            # NOT allowed -- would rebind a tuple slot
Traceback (most recent call last):
TypeError: 'tuple' object does not support item assignment

This same shallow-immutability principle is exactly why a tuple containing a list is not hashable — see 11.9 Immutability and Copying.

Quick Interview Answer

“A tuple’s immutability protects its own slots — which object each position refers to — but says nothing about what that object does internally. t = (1, 2, [3, 4]) can never have t[2] reassigned to a different object, but the list at t[2] is still just an ordinary mutable list, and t[2].append(99) works fine. This is the single most misunderstood thing about tuples: ‘immutable’ means the container’s own bindings are frozen, not that everything reachable through it is frozen too — and it’s exactly why a tuple holding a list can’t be hashed, since its effective contents could still silently change out from under a dict or set that was keying on it.”

Common Mistakes

  • Describing a tuple as “fully immutable” without the shallow-immutability caveat — it’s a very common wrong answer to “can a tuple ever change?”
  • Assuming t[2].append(99) is disallowed because it “modifies the tuple” — it doesn’t modify the tuple at all; the tuple still points at the exact same list object before and after.
  • Trying to hash a tuple that contains a list and being surprised by TypeError: unhashable type: 'list' — the tuple’s own hashability depends entirely on whether every element it holds is itself hashable.

Add More Questions to This Guide

Know a question that should be here? Share it and help the community!

Open Google Form