Tuples: immutability and use cases

RoadmapsPython

Overview

A tuple is an ordered, immutable sequence. You create one with parentheses or just commas — the commas are what actually make the tuple, not the parentheses: coords = (40.7128, -74.0060) same = 40.7128, -74.0060 A single-element tuple REQUIRES a trailing comma — without it Python sees plain parentheses: one = (42,) # tuple with one int not_a_tuple = (42) # just the int 42 Because tuples are immutable, you cannot append, remove, or reassign an element after creation. But immutability makes tuples hashable (as long as every element inside is also hashable), so they can serve as dict keys or set members: cache = {} cache[('users', 'page', 2)] = [{'id': 7}, {'id': 8}] One sharp edge: immutability applies to the tuple's SLOTS, not to the objects inside them. A tuple can hold a mutable object, and that object can still be mutated in place — you just cannot rebind the slot: row = (7, ['pending']) row[1].append('paid') # legal — mutates the inner list row[1] = [] # TypeError — cannot rebind a slot A tuple like that is also NOT hashable (the inner list breaks it), so it cannot be a dict key. Tuple unpacking lets you extract elements into named variables in one step: status, body = (200, {'ok': True}) This is why functions that return multiple values actually return a tuple — `return status, body` packs them, and the caller unpacks. Think of a tuple as a sealed envelope: once you put items inside and close it, you can read the contents but cannot swap, add, or remove anything. That seal is what makes it safe to use as a dict key.

Tuples give you a lightweight, read-only container for fixed-size data: coordinates, status-and-body pairs, composite cache keys. Their immutability guarantees the data will not change by accident, and their hashability lets you use multi-part keys in dicts and sets — something a list cannot do.

Where used: FastAPI returning (status, body) pairs, Database row results from cursor.fetchall(), Composite dict keys for caching and lookups

Why learn this

Code walkthrough

row = ('srv-1', 8080, 'healthy')
host, port, status = row
print(host)
print(port)
print(status)
print(type(row))

Focus: Unpacking assigns each tuple element to a named variable in one step — host, port, status each get their value from the corresponding position in row.

Aha moment

a = (1, 2, [3, 4])
a[2].append(5)
print(a)

Prediction: Tuples are immutable. What happens when you try to mutate the list inside the tuple?

Common guess: TypeError — you cannot change a tuple

The tuple is immutable: you cannot reassign a[2] to a different object. But the list AT a[2] is still a mutable object — you can change its contents. Immutability freezes the references in the tuple, not the objects those references point to.

Common mistakes

Glossary

hashable
An object that has a fixed value that never changes during its lifetime, allowing it to be used as a dictionary key or set item. Example: `cache[('users', 1)] = data`.
unpacking
Extracting multiple items from a collection, like a tuple or list, and assigning them to separate variables all at once. Example: `host, port = ('localhost', 8080)`.

Recall questions

Understanding checks

What will this code print?

<class 'int'>

Without a trailing comma, `(42)` is just the integer 42 wrapped in parentheses. You need `(42,)` to create a tuple.

Why can a tuple be used as a dictionary key, but a list cannot?

Because tuples are immutable and hashable (as long as all their contents are hashable), whereas lists are mutable.

Dictionary keys must be hashable, which requires them to remain unmodified throughout their lifetime.

Practice tasks

Composite cache key

The get_cached function currently uses a string key for caching. Modify its behavior to use a tuple of (tenant, resource, page) as the dictionary key instead, which is safer and faster.

Challenge

Build a request-rate counter by endpoint

Write count_requests(logs) where logs is a list of (method, path) tuples like [('GET', '/users'), ('POST', '/users'), ('GET', '/users')]. Return a dict mapping each (method, path) tuple to its count. Print the result for a sample log list.

Continue learning

Previous: Primitive types: int, float, bool, str

Previous: Mutable vs immutable objects

Previous: Lists: indexing, slicing, methods

Next: Time Complexity of Collection Operations

Return to Python Roadmap