Why can tuples contain mutable items?
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Python tuples are described as immutable, yet you can put a list inside a tuple and then modify that list. This surprises many developers the first time they encounter it. The behavior makes perfect sense once you understand what "immutable" actually means for a tuple. This article explains the distinction between an object's identity and its value, why tuples store references rather than copies, and the practical consequences of putting mutable objects inside tuples.
What Immutability Really Means for Tuples
When Python says a tuple is immutable, it means that the tuple's structure cannot change after creation. You cannot add elements, remove elements, or reassign a slot to point to a different object. However, immutability applies to the tuple itself, not to the objects it contains.
A tuple holds references (pointers) to objects. Immutability guarantees that those references will never change. The reference in slot 0 will always point to the same object. But if that object happens to be mutable, the object itself can still change through its own methods.
The tuple does not own a copy of the list. It holds a reference to the original list object. The list continues to live its own life, and the tuple simply points to it.
Identity vs. Value
Python distinguishes between an object's identity (its memory address, checked with is) and its value (checked with ==). Immutability for a tuple means the identities of its elements are fixed. The values of those elements can change if the elements themselves are mutable.
The identity of my_tuple[0] never changed. It still refers to the exact same list object. The list's contents changed, but the tuple's reference did not.
Why Python Allows This
Python could, in theory, perform a deep copy of every object placed into a tuple, making the contents truly frozen. But that would be expensive and would break the reference semantics that Python relies on everywhere.
Consider a tuple used as a lightweight record to group related data. If the tuple deep-copied everything, modifying the original list would not update the tuple's version, which would be confusing in a different way. Python chose consistency: all containers store references, and immutability only applies to the container's own structure.
The Hashability Consequence
One practical consequence is that tuples containing mutable items are not hashable. Python requires that hashable objects have a hash value that never changes during their lifetime. Since a list inside a tuple can change, the tuple's effective value can change, which would violate the hash contract.
This means you cannot use a tuple containing a list as a dictionary key or add it to a set.
Augmented Assignment Surprise
One particularly tricky edge case involves the += operator on a list inside a tuple.
The list actually gets modified because += calls list.extend() first, which succeeds. Then Python tries to assign the result back to t[0], which fails because tuples do not support item assignment. So you end up with a modified list and a raised exception. This is a well-known Python gotcha documented in the official FAQ.
Common Pitfalls
Assuming tuples are deeply immutable. Tuples guarantee structural immutability only. If you need a fully frozen data structure, use a tuple of immutable elements (strings, numbers, other tuples) or convert mutable items with tuple() or frozenset().
Using tuples with mutable elements as dict keys. This will raise a TypeError at runtime. Always verify that all elements in a tuple are hashable before using the tuple as a key.
Relying on copy behavior. Placing a list in a tuple does not create a copy. If you modify the original list variable, the change is visible through the tuple as well. If you need isolation, pass list(original) to create a shallow copy.
Confusing += with .append(). Use t[0].append(value) to modify a list inside a tuple safely. The += operator triggers an assignment step that raises a TypeError, even though the underlying list mutation still occurs.
Summary
Tuples are immutable in the sense that their structure, the sequence of references they hold, is fixed after creation. However, the objects those references point to can be mutable and can change independently. This is because Python containers store references, not copies. The practical upshot is that a tuple containing a mutable item like a list is not hashable and cannot serve as a dictionary key or set member. If you need a truly frozen container, ensure every element inside the tuple is itself immutable.
Related reading
- Why can't I build a list by assigning each element in turn? How can I add append the elements without getting an IndexError?
- Why can''t I use a list as a dict key in python? Exactly what can and cannot be used, and why?
- Why can't Prim's or Kruskal's algorithms be used on a directed graph?
- Why charset names are not constants?
- Why can't a 'continue' statement be inside a 'finally' block?
- Why can't dataclasses have mutable defaults in their class attributes declaration?
- Why deletion of elements of hash table using doubly-linked list is O1?
- Why DFS and not BFS for finding cycle in graphs

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.