Tuples as Immutable Records and Hashable Keys
15 min · Beginner
Need help? Ask a tutor on WhatsApp (opens in a new tab)While lists are designed for homogeneous collections of changing length, tuples represent fixed, immutable records. Because tuples cannot change, Python optimizes their memory footprint and allows them to serve as hashable keys in sets and dictionaries.
Tuples vs Lists: Memory Layout
Tuple is an ordered, fixed-length collection of items. Once it is created, you cannot add, remove or replace its items.
Tuples have zero over-allocation slack space. Their pointer array matches the exact element count.
import syst = (1, 2, 3)l = [1, 2, 3]print("Tuple size:", sys.getsizeof(t))print("List size: ", sys.getsizeof(l))Example 1 · List and tuple size
import sys
marks_list = [72, 85, 91]marks_tuple = (72, 85, 91)print("list :", sys.getsizeof(marks_list), "bytes")print("tuple:", sys.getsizeof(marks_tuple), "bytes")list : 88 bytes tuple: 64 bytes
What this code does
- The tuple is smaller because it has no spare slots.
- Exact byte counts depend on the Python version, so treat them as a sample.
Tuples consume significantly less RAM and are allocated via a freelist in CPython, making small tuple creation exceptionally fast.
Tuples as Composite Dictionary Keys
Hashable describes a value with a fixed hash number that never changes, so it can be a dictionary key or a set member.
Because lists are unhashable, you cannot use a list as a dictionary key. Tuples (containing hashable elements) are hashable and ideal for multidimensional coordinates and composite keys.
# Grid coordinate mappinggrid = {}grid[(0, 0)] = "Start"grid[(4, 5)] = "Treasure"grid[(9, 9)] = "Goal"
print("Target at (4, 5):", grid[(4, 5)])Example 2 · Price list by product and region
prices = { ("laptop", "IN"): 55000, ("laptop", "US"): 799, ("phone", "IN"): 18000,}key = ("laptop", "US")print(prices[key])print(("tablet", "IN") in prices)799 False
What this code does
- Each key is a (product, region) pair, so one dictionary holds two dimensions.
inchecks the whole tuple key in O(1) on average.
This pattern is widely used in graph algorithms, spatial grids, and multi-column database caching.
Extended Star Unpacking
Unpacking assigns the items of a tuple or list to separate names in one statement, such as lat, lon = coords.
Python allows unpacking arbitrary segments of tuples using the star * operator.
record = ("IND", 2026, 95.5, "Aarav", "Verified")country, year, score, *rest = recordprint(f"{country} ({year}): score {score} | Extra: {rest}")Example 3 · Drop the best and worst marks
marks = [88, 92, 75, 60, 95]first, *middle, last = marksprint(first, middle, last)print("Middle total:", sum(middle))88 [92, 75, 60] 95 Middle total: 227
What this code does
*middlecollects everything between the first and last values into a list.- Unpacking works on any sequence, not only tuples.
*rest gathers any remaining elements into a clean list.
Structured Records with namedtuple
namedtuple is a factory in the collections module that builds a tuple type whose positions also have names.
collections.namedtuple assigns names to each position, giving you tuple memory efficiency with attribute access.
from collections import namedtuple
Point2D = namedtuple("Point2D", ["x", "y"])pt = Point2D(10, 25)print(f"X: {pt.x}, Y: {pt.y}")print(pt[0]) # Still accessible by index!Example 4 · A record with names
from collections import namedtuple
City = namedtuple("City", ["name", "country", "population"])bengaluru = City("Bengaluru", "India", 13.6)print(f"{bengaluru.name} ({bengaluru.country}): {bengaluru.population}M")print("Is tuple:", isinstance(bengaluru, tuple))Bengaluru (India): 13.6M Is tuple: True
What this code does
Citycreates a namedtuple subclass.- Attributes are accessible via
.nameor[0]. - Instances inherit full tuple immutability and hashability.
Namedtuples combine readability with the immutability and speed of tuples.
Immutable, but only one level deep
Shallow immutability means a tuple never changes which objects it holds, but a mutable object inside it can still change.
A tuple fixes its pointers, not the objects behind them. A list inside a tuple can still change, and that also makes the tuple unhashable.
record = ("A-1", [3, 4])record[1].append(5)print(record)
try: hash(record)except TypeError as error: print("Cannot hash:", error)Example 5 · Hashing a record
safe = ("A-1", 3)risky = ("A-1", [3])print(hash(safe) == hash(("A-1", 3)))try: hash(risky)except TypeError as error: print("Unhashable:", error)True Unhashable: unhashable type: 'list'
What this code does
- Equal tuples of immutable items give equal hashes.
- A list inside the tuple makes the whole tuple unhashable.
Use only immutable items (numbers, strings, other tuples) inside a tuple that must act as a dictionary key.
Next step
Check your understanding
10 quick questions