Python Tuples ()
Learn about Immutable Sequences with deep memory architecture and step-by-step breakdowns.
A tuple in Python is a built-in, immutable, ordered sequence of elements. "Immutable" means that once a tuple is created in memory, its size and the pointers it contains can never be changed, added to, or removed from.
Why do we need this when we have Lists? Lists are heavy, dynamic, and have overhead to allow for growing and shrinking. Tuples are hardcoded. Because Python knows a tuple will never change size, it optimizes them aggressively in memory, making them significantly faster and safer for fixed data structures (like coordinates or RGB colors) than lists.
Think of a List as a whiteboard. You can write names on it, erase them, and write new ones whenever you want.
Think of a Tuple as words carved into a stone tablet. Once the stone is carved, you cannot erase a word, add a new word, or change the order. If you want a different list of words, you must throw away the stone tablet and carve an entirely new one.
This "stone tablet" guarantee allows the Python engine to skip checking for changes, passing data around the program with zero fear of accidental corruption.
# 1. Tuple Creation (Packing)
coordinates = (34.0522, -118.2437, "Los Angeles")
# 2. Accessing Elements (Indexing)
latitude = coordinates[0]
# 3. Tuple Unpacking
lat, lon, city = coordinates
# 4. Attempting to Mutate (Will cause an error)
try:
coordinates[0] = 40.7128
except TypeError as e:
print(f"Error: {e}")
| Code Line | Explanation |
|---|---|
coordinates = (34.0522, -118.2437, "Los Angeles") |
Python allocates a fixed block of memory to store three pointers. One points to a float (34.0522), one to a float (-118), and one to a string object ("Los Angeles"). This operation is called "packing". |
latitude = coordinates[0] |
Python instantly looks up memory offset 0 within the tuple via O(1) time complexity and returns the float 34.0522. |
lat, lon, city = coordinates |
This is called "unpacking". Python evaluates the right side (a 3-item sequence) and sequentially binds the three variables on the left side to the three objects stored inside the tuple. |
coordinates[0] = 40.7128 |
This operation is strictly forbidden. The
TypeError: 'tuple' object does not support item assignment is thrown
immediately because the tuple's internal C-struct does not contain any code for
mutation. |
Input Operation: Unpacking
Code: a, b = ("Apple", "Banana")
Transformation: The tuple container is dissolved in the local namespace, routing its internal pointers directly to separate variable names.
Output State:
a -> "Apple" (String object)
b -> "Banana" (String object)
Internally in CPython, a tuple is mathematically represented as an array of
PyObject * (pointers) embedded directly inside a PyTupleObject
C-struct.
Because there is no need to ever resize it, Python allocates exactly the number of bytes needed for the length of the tuple. Lists, on the other hand, allocate massive hidden buffer spaces (over-allocation) to prepare for `append()` calls. Tuples have exactly 0 wasted bytes.
Memory structure of t = (10, 20):
[ PyTupleObject Header ]
[ Ob_Size = 2 ]
[ Pointer 0 ----------]-> [ PyLongObject: 10 ]
[ Pointer 1 ----------]-> [ PyLongObject: 20 ]
Notice there is no `capacity` field, only `size`. The pointers themselves cannot be rerouted after creation.
Tuples are 1-Dimensional. However, you can nest tuples to create N-Dimensional strict structures.
grid = ((1, 2), (3, 4)) simulates a 2x2 immutable matrix.
Use len(t) to get the 1D length.
Object Type: <class 'tuple'>
Important Rule regarding Functions: If you write a Python function that uses
return a, b, Python automatically silently packs them into a single Tuple
before returning them. Functions in Python always return exactly ONE object, but
returning a tuple allows you to simulate returning multiple values!
The One-Element Tuple Trap: Writing t = (5) does NOT create a
tuple. Python interprets the parentheses as mathematical grouping, so t becomes
the integer 5.
Solution: You MUST include a trailing comma: t = (5,).
The "Immutable" Illusion: If a tuple contains a mutable object, like a list,
that inner object CAN be mutated! t = (1, [2, 3]). You cannot change the
pointer at index 1 to point to a new list, but you CAN do t[1].append(4). The
tuple only guarantees the pointer identities won't change, not the underlying data
of the connected objects.
collections.namedtuple: A brilliant variation that allows you
to access tuple elements by name instead of index.
Point = namedtuple('Point', ['x', 'y']). p = Point(10, 20). Now
you can do p.x and p.y while maintaining the high performance of a
tuple.
Mistake: Trying to add items to a tuple.
t = (1, 2)t = t + (3,)
Why is this bad?: This works, but it does NOT modify the original tuple. It destroys the original tuple and builds an entirely new 3-element tuple in memory, scanning and copying all old elements to the new memory block. O(N) penalty. Do not do this in a loop!
Tuple Caching (Freelists): Python maintains a secret "freelist" cache of tuples up to length 20. If you delete a size-3 tuple, Python does not give the memory back to the OS. It saves the empty C-struct. The next time you create a size-3 tuple, it instantly reuses the cached struct without invoking the slow OS `malloc()`.
Result: Creating a tuple is significantly faster than creating a List.
Challenge: Write a single line of Python code to swap the values of two
variables a = 10 and b = 20 without using a third temporary
variable like temp.
Expected Answer: a, b = b, a (This works because Python packs
`b` and `a` into an invisible tuple on the right, and instantly unpacks them into the
variables on the left!)
Why can Tuples be used as Dictionary Keys, but Lists cannot?
Dictionaries rely on Hashing—converting data into a fixed numerical fingerprint to instantly find memory buckets. A hash value mathematically relies on the fact that the underlying data will never change. Since a List is mutable, its hash could theoretically change while it's inside the dictionary, destroying the entire hash table lookup mechanism. Because tuples are immutable, Python allows them to generate a permanent hash value, making tuples valid dictionary keys!