A tuple fixes its sequence of references, but objects reached through those references can remain mutable.
Python tuples: immutable containers can still contain mutable state
Operation contract
The import identity groups a tenant label with a mutable rejection list. Appending to the nested list changes reachable state even though the tuple itself cannot replace either slot. A separate tuple containing only the tenant string and an integer identifier is suitable as a dictionary key because those components satisfy the hashing contract.
Failure and ownership boundary
Immutability and hashability are separate requirements. A tuple containing a list is unhashable, and an immutable outer shape does not make its reachable object graph read-only. Use Python dictionaries: insertion order and duplicate-key replacement deliberately and choose Python dataclasses: frozen fields require an immutable value model according to the ownership promise.
Working program
import_state = ("tenant-a", [])
import_state[1].append("R41")
print(import_state)
receipt_key = ("tenant-a", 41)
print({receipt_key: 125}[receipt_key])
try:
hash(import_state)
except TypeError:
print("mutable component is unhashable")Output
('tenant-a', ['R41'])
125
mutable component is unhashableCosts and limits
Tuple construction stores references proportional to its length. Hashing also depends on component work; it is not free merely because the outer container cannot be edited.
Common Mistakes
- Immutable outer slots do not freeze nested values.
- Check every key component’s hashing contract.
Connected lessons
Python dictionaries: insertion order and duplicate-key replacement, Python dataclasses: frozen fields require an immutable value model, Java records with arrays: copy on input and output.
Follow the related contract
Python namedtuple records: immutable fields can still hold mutable objects.
