094. Variable Unpacking
Destructure sequences and iterables into named variables
094. Variable Unpacking
Rohan’s snapshot dict has a "top_processes" list — each entry is a tuple of (name, pid, rss_mb). Extracting fields with index access is noisy.
Before:
for proc in snapshot["top_processes"]:
name = proc[0]
pid = proc[1]
rss = proc[2]
print(f"{name} (PID {pid}): {rss} MB")After unpacking:
for name, pid, rss in snapshot["top_processes"]:
print(f"{name} (PID {pid}): {rss} MB")He also uses star unpacking to split the list into the top process and the rest:
top, *rest = snapshot["top_processes"]
name, pid, rss = top
print(f"Biggest: {name} using {rss} MB")
print(f"{len(rest)} other processes")And when get_stats() returns (min_mb, max_mb, avg_mb), he unpacks immediately:
# Before:
stats = get_stats(snapshots)
min_mb = stats[0]
max_mb = stats[1]
# After:
min_mb, max_mb, avg_mb = get_stats(snapshots)The rule: If you find yourself writing
x[0],x[1],x[2]for a known-length sequence, unpacking is cleaner, more readable, and will raise a ValueError immediately if the sequence has the wrong length — a free consistency check.
💡 Fun fact: Python’s a, b = b, a swap — with no temporary variable — works because Python evaluates the entire right-hand side as a tuple before any assignment happens. This was one of Python’s earliest elegant features, borrowed from ABC (Guido’s earlier language). In C, the classic interview question is “swap without a temp variable” using XOR — Python makes it a one-liner with no tricks.
⚠️ Watch out: The most common unpacking mistake is a length mismatch — a, b = [1, 2, 3] raises ValueError: too many values to unpack. This is actually a feature (it catches unexpected data shapes), but beginners are surprised when their “unpack three values” code breaks after an API adds a fourth field. Star unpacking (a, b, *rest = items) is the safe alternative when the length might vary.
🤔 Think about it: first, *_, last = items discards the middle values into _. The convention of using _ for “I don’t care about this” is widely adopted in Python. Is this just convention, or does Python actually treat _ specially? What happens if you write first, *_, last = items and then accidentally use _ later in the function?
Learning objectives
- Unpack tuples and lists into named variables
- Use star unpacking to capture variable-length sequences
- Swap values without a temporary variable
- Use _ to discard unwanted values during unpacking
Key concepts
- unpacking
- star unpacking
- tuple assignment
- destructuring
Try it
Concept detail
Tuple/sequence unpacking: a, b = (1, 2) assigns a=1, b=2 in one statement.
Swap without a temp variable: a, b = b, a Python evaluates the right side first, then assigns left-to-right.
Star unpacking — captures variable-length middle: first, *rest = [1, 2, 3, 4] → first=1, rest=[2, 3, 4] *start, last = [1, 2, 3, 4] → start=[1, 2, 3], last=4 first, *, last = [1, 2, 3, 4] → first=1, last=4, middle ignored a, *, b = items — _ is convention for “I don’t need this”
Works on any iterable: a, b, c = “xyz” → a=‘x’, b=‘y’, c=‘z’ for k, v in d.items(): → unpack (key, value) pairs in a for loop
Multiple return values use unpacking: def get_bounds(): return 10, 90 # returns a tuple lo, hi = get_bounds() # unpacks the tuple immediately
Nested unpacking: (a, b), c = (1, 2), 3 → a=1, b=2, c=3 Useful when iterating over lists of tuples.
Mismatch raises ValueError: a, b = [1, 2, 3] # ValueError: too many values to unpack This is a feature — it catches unexpected data shapes immediately.
Solution
def swap(a, b):
return b, a
def first_last(items):
first, *_, last = items
return first, last
def split_head_tail(items):
head, *tail = items
return head, tailTests
def test_swap():
assert swap(1, 2) == (2, 1)
assert swap("hello", "world") == ("world", "hello")
def test_first_last_two():
assert first_last([10, 20]) == (10, 20)
def test_first_last_many():
first, last = first_last([1, 2, 3, 4, 5])
assert first == 1
assert last == 5
def test_split_head_tail():
head, tail = split_head_tail([1, 2, 3, 4])
assert head == 1
assert tail == [2, 3, 4]
def test_split_two_items():
head, tail = split_head_tail([10, 20])
assert head == 10
assert tail == [20]