Looping over a dict
Data travels in pairs and small fixed groups constantly: a point's (x, y), a row's (name, score), and every entry of a dict. This lesson covers the loop that processes a whole dict and the tuple, Python's type for those fixed little groups, together, because dict iteration hands you tuples.
Three views of a dictionary, three loops:
for name in ages: # keys (the default) for age in ages.values(): # values only for name, age in ages.items(): # pairs: the one you will use most
That two-variable form works because .items() hands out each pair as a tuple.
Tuples: sequences that never change
A tuple is written with parentheses: point = (3, 4). Index and slice it like a list, but it is immutable: point[0] = 9 is a TypeError. Use tuples for small fixed records where each position means something, like (x, y) or (name, score).
Unpacking splits a tuple into variables in one line, and it is why the .items() loop reads so well:
x, y = (3, 4) # x is 3, y is 4 a, b = b, a # the classic swap, no temp variable
Unpacking pairs, and swapping values
The loop below takes each pair from .items() and splits it straight into two named variables. The last two lines show the same unpacking used for a swap.
ages = {"Ada": 36, "Grace": 45, "Alan": 41}
for name, age in ages.items():
print(f"{name} is {age}")
a, b = 1, 2
a, b = b, a
print(a, b)Output
Ada is 36 Grace is 45 Alan is 41 2 1
Writing for name, age in ... is what makes the body readable, since both halves of each entry arrive already named. Without unpacking the loop would have to index into a tuple, which reads worse and says less.
The swap works because the right-hand side is evaluated completely before any assignment happens. Both original values are captured first, then handed back in the opposite order, which is why no temporary variable is needed.
Running t = (1, 2, 3) and then t[0] = 99 raises a TypeError, because tuples cannot be changed.
Immutability here works exactly as it does for strings. Item assignment is simply not an operation tuples support, so the attempt fails immediately rather than partially succeeding. Code that genuinely needs to modify items wants a list instead.
Immutability is a feature rather than a limitation, though. Because a tuple's contents cannot shift underneath anyone, a tuple can serve as a dictionary key, which a list can never do. That makes tuples the usual way to key data by a coordinate pair or any other small composite identifier.
A list of tuples is how tabular data usually arrives, and unpacking in the for line names both fields at once.
cart = [("apple", 3), ("banana", 2), ("milk", 1)] total = 0 for item, qty in cart: print(f"{item}: {qty}") total += qty print(total)
Output
apple: 3 banana: 2 milk: 1 6
Each pass receives one tuple and splits it into item and qty, so the body reads in terms of what the values mean rather than where they sit. The accumulator follows the pattern from lesson 5-3, created before the loop and updated on every pass, which lets one loop both print each line and build the total. Because the print(total) sits outside the loop, it reports the finished sum of 6 rather than a running one.
Turning pairs into a dict
Converting a list of pairs into a dictionary is a shape change you will perform constantly with real data, usually to make later lookups cheap.
cart = [("apple", 3), ("banana", 2), ("milk", 1)] stock = {} for item, qty in cart: stock[item] = qty print(stock) print(stock["banana"])
Output
{'apple': 3, 'banana': 2, 'milk': 1}
2The loop unpacks each tuple and stores the quantity under the item's name, adding one entry per pair. What this buys is the second print: asking the list for the banana quantity would mean scanning tuples until a name matched, while the dict answers directly by key.
One consequence to keep in mind is that duplicate names would collapse. If cart contained apple twice, the later entry would overwrite the earlier one rather than combining them, so summing duplicates would call for stock.get(item, 0) + qty instead.