Dict and set comprehensions
In the previous lesson, the conveyor put the tiles into a list box. Now let's change what stands at the end of the belt. Say the press stamps each tile with a label and a number under it. The tiles go into a card index where you find a number by its label. That is a dict, and it has its own comprehension—in curly braces.
You have already built a dict with a loop: an empty dict, then a value written under a key on each iteration. Compare such a loop with a comprehension:
words = ["apple", "fig", "kiwi"]
lengths = {}
for w in words:
lengths[w] = len(w)
print(lengths) # {'apple': 5, 'fig': 3, 'kiwi': 4}
lengths = {w: len(w) for w in words}
print(lengths) # {'apple': 5, 'fig': 3, 'kiwi': 4}Let's go through both versions:
- The loop creates an empty dict
lengthsand runslengths[w] = len(w)for each word. - The comprehension
{w: len(w) for w in words}makes the same writes by itself. - Both versions print
{'apple': 5, 'fig': 3, 'kiwi': 4}.
In a dict comprehension, a "key: value" pair with a colon comes before for. Each iteration adds one pair to the dict, like the assignment lengths[w] = len(w) in the loop. The order of work is the same as in a list comprehension. First comes for, then the if filter if there is one, and the pair on the left comes last.
Three examples in curly braces
Curly braces can do more than move words into a dict. This example holds three comprehensions:
words = ["ox", "to", "sun"]
print(sorted({len(w) for w in words})) # [2, 3]
prices = {"pear": 70, "plum": 40}
print({k: v * 2 for k, v in prices.items()}) # {'pear': 140, 'plum': 80}
print({k: v for k, v in prices.items() if v > 50}) # {'pear': 70}A set
If a single expression without a colon comes before for, you get a set comprehension. On the conveyor, it is a box that does not accept a second tile with the same number.
The word lengths here are 2, 2 and 3. A set stores each value once, so the two lengths 2 gave one element. A set has no order, so it is wrapped in sorted for printing.
New values from items()
The header for k, v in prices.items() loops over the pairs of the dict. Unpacking spreads each pair over two names, as in an ordinary loop.
The comprehension {k: v * 2 for k, v in prices.items()} keeps the keys and doubles the prices. You get a new dict, and prices does not change.
A filter on the value
An if filter after for works here the same way as in a list comprehension. The dict {k: v for k, v in prices.items() if v > 50} keeps only the pear: it costs more than 50, and the plum costs less.
Pairs from zip
Keys and values often sit in two lists of the same length. The zip function joins them into pairs, and the comprehension spreads each pair into a key and a value.
Take names = ["ann", "bob"] and scores = [90, 75]. The form {n: s for n, s in zip(names, scores)} gives {'ann': 90, 'bob': 75}. If the lists differ in length, zip stops at the shorter one, and the extra keys do not get into the dict.
A repeated key
This is where the card-index analogy stops working. In a real card index, two cards with the same label can stand side by side. In a dict, a key appears once, and a second pair with the same key is not added: it replaces the value.
There is no error. Like the assignment d[k] = v in a loop, the later pair replaces the value, and the key stays in its old place:
names = ["anna", "bob", "alex"]
by_letter = {n[0]: n for n in names}
print(by_letter) # {'a': 'alex', 'b': 'bob'}
print(len(by_letter)) # 2Let's go step by step:
- The first iteration stores
"anna"under the key"a". - The second adds
"bob"under the key"b". - The third gives the same key
"a"and replaces"anna"with"alex".
That is why the dict holds two pairs, not three, and the key "a" comes first, where the first iteration wrote it. Interviewers like to ask how many pairs a dict ends up with when keys repeat.
Common mistake
The key and the value are separated by a comma instead of a colon:
words = ["apple", "fig", "kiwi"]
lengths = {w, len(w) for w in words} # ✗SyntaxError: did you forget parentheses around the comprehension target?Before for inside curly braces, Python expects a pair with a colon or a single expression, and w, len(w) is two expressions. So the file does not run. The parentheses from the hint would give a set of tuples {(w, len(w)) for w in words}, not a dict. The colon gives a dict: {w: len(w) for w in words}.
Key points
- The dict comprehension
{w: len(w) for w in words}puts a pair with a colon beforefor. - Without a colon, curly braces give a set, and repeats disappear from it.
- When a key repeats, the later pair replaces the value, and the key keeps its first place.
- A comma instead of a colon between the key and the value is a
SyntaxError.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.