055. Tuples
Immutable records for fixed-structure data
055. Tuples
Aryan’s RAM monitor stores each memory reading as a tuple so it can never be accidentally modified after capture:
import time
def take_reading():
mem = psutil.virtual_memory()
# (timestamp, total_gb, used_gb, percent)
return (time.time(), mem.total / 1e9, mem.used / 1e9, mem.percent)
history = []
for _ in range(10):
history.append(take_reading())
time.sleep(1)
# Unpack cleanly at use site
for ts, total, used, pct in history:
print(f"{ts:.0f} {used:.1f}/{total:.1f} GB ({pct}%)")Tuples are the right container here because:
- The fields are positional and fixed — there will always be exactly 4.
- Immutability guarantees that a historical reading can never be altered.
- Tuples can be used as dict keys (e.g.,
cache[(pid, timestamp)] = rss_mb), lists cannot.
When Aryan returns (min_proc, max_proc) from a helper function, Python packs it as a tuple automatically. The caller unpacks with lo, hi = f().
💡 Fun fact: Tuples are hashable (as long as all their elements are hashable), which is why they can be used as dictionary keys. This makes tuples the natural choice for composite keys: cache[(pid, timestamp)] works, but cache[[pid, timestamp]] raises a TypeError because lists are not hashable. This hashability distinction between tuples and lists is one of the most practically important differences between the two types.
⚠️ Watch out: A one-element tuple requires a trailing comma — (42,) is a tuple, but (42) is just the integer 42 in parentheses. Forgetting the comma is an extremely common mistake: point = (5) gives you an int, not a tuple, and point[0] will raise TypeError: 'int' object is not subscriptable.
🤔 Think about it: Tuples are immutable, so you can’t do point[0] = 10 to update an x-coordinate. If you have a tuple (3, 4) and want to change it to (10, 4), you have to create a new tuple. Does this immutability make tuples harder to work with, or does it actually make programs safer — and can you think of a real scenario where accidentally mutating a coordinate caused a bug?
Learning objectives
- Create tuples with ()
- Access tuple elements with indexing
- Unpack tuples with multiple assignment
Key concepts
- tuple
- immutable
- unpacking
Try it
Concept detail
Tuples are immutable ordered sequences. Created with (1, 2, 3) or tuple([1, 2, 3]). A one-element tuple: (42,) — the comma is required! (42) is just the integer 42.
Immutable means: no append/remove, no item assignment. But you can concatenate: (1, 2) + (3, 4) == (1, 2, 3, 4)
Unpacking: a, b = (1, 2) # basic x, *rest = (1, 2, 3, 4) # x=1, rest=[2,3,4] _, second, _ = (1, 2, 3) # discard first and third
When to use tuples vs lists: Tuple — fixed structure, positional meaning (x,y), function return values, dict keys, “this data should not change” List — variable length, homogeneous items, needs append/remove
Tuples are slightly faster than lists and signal immutability to the reader. Functions that return “two things” implicitly return a tuple: return a, b.
Solution
import math
def make_point(x, y):
return (x, y)
def distance(p1, p2):
return math.sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2)
def midpoint(p1, p2):
return ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)
def swap(point):
return (point[1], point[0])Tests
def test_make_point_is_tuple():
p = make_point(3, 4)
assert type(p) == tuple
assert p == (3, 4)
def test_distance_345():
# 3-4-5 right triangle
p1 = (0, 0)
p2 = (3, 4)
assert abs(distance(p1, p2) - 5.0) < 0.001
def test_distance_zero():
assert distance((2, 3), (2, 3)) == 0.0
def test_midpoint():
assert midpoint((0, 0), (4, 6)) == (2.0, 3.0)
def test_swap():
assert swap((3, 7)) == (7, 3)
def test_tuple_unpacking():
x, y = make_point(10, 20)
assert x == 10 and y == 20