Dict and set comprehensions in Python follow the same grammar as a list comprehension — you just change the brackets and, for a dict, write a key and a value separated by a colon. That small change turns "build a new list" into "build a new mapping" or "build a new collection of unique values" without leaving expression land.
What does a dict comprehension look like?
Curly braces, then key_expression: value_expression, then for, then the target and the iterable.
scores = {"ada": 91, "grace": 88, "alan": 95}
doubled = {name: score * 2 for name, score in scores.items()}
print(doubled)
passed = {name: score for name, score in scores.items() if score >= 90}
print(passed)
Everything you learned about list comprehensions carries over. The filter still runs before the expression. The result still follows the order of the source. And the comprehension still builds a brand-new dictionary, leaving the original alone.
One thing the dict version adds is that the key expression can be computed. You are not limited to reusing an existing key — you can build a new one from the value.
scores = {"ada": 91, "grace": 88}
upper = {name.upper(): score for name, score in scores.items()}
print(upper)
How do you build a dict comprehension from lists or pairs?
When your data arrives as two parallel lists, zip them and unpack each pair. The key comes from the left of the colon and the value from the right.
names = ["ada", "grace", "alan"]
scores = [91, 88, 95]
report = {name: score for name, score in zip(names, scores)}
print(report)
For data that is already a list of pairs, unpack each pair instead. This is the shape you get from a database query or a CSV file parsed into rows.
rows = [("ada", 91), ("grace", 88), ("alan", 95)]
report = {name: score for name, score in rows}
print(report)
Both of these are equivalent to dict(zip(names, scores)). The comprehension version is better when you want to transform on the way in, or when you need to filter. When you do not, dict(zip(...)) is shorter and reads just as clearly.
How do you invert a dictionary?
Swap the key and the value in the comprehension.
prices = {"apple": 2, "pear": 3, "plum": 2}
inverted = {price: name for name, price in prices.items()}
print(inverted)
Look closely at the result. "plum" has vanished, because "apple" and "plum" both cost 2, and a dictionary can hold only one entry per key. The last value written for a key wins.
That is not a bug in the comprehension; it is a property of dictionaries, and it is the thing to check whenever you build a mapping keyed by something that is not guaranteed to be unique. If the values must be unique, inverting is safe. If they might not be, collect the names into a list instead.
prices = {"apple": 2, "pear": 3, "plum": 2}
grouped = {}
for name, price in prices.items():
grouped.setdefault(price, []).append(name)
print(grouped)
How do you build nested structures with comprehensions?
Put one comprehension inside the key or value expression of another. The inner one is written first in the sense that it is evaluated for every outer item.
matrix = [[1, 2], [3, 4]]
indexed = {
row_index: {col_index: number * number for col_index, number in enumerate(row)}
for row_index, row in enumerate(matrix)
}
print(indexed)
That produces a mapping from row index to a mapping from column index to the squared value. Nested comprehensions get hard to read quickly, though, so this is the point where a couple of clearly named loops may serve you better than a single dense expression.
The same nesting idea works for grouping, though defaultdict usually does it with less code. Here is the comprehension version and the standard-library version side by side.
from collections import defaultdict
words = ["apple", "avocado", "banana", "blueberry", "cherry"]
grouped = defaultdict(list)
for word in words:
grouped[word[0]].append(word)
print(dict(grouped))
What is a set comprehension for?
For producing unique values from a sequence, optionally with a transformation applied first. It is a set literal with a for clause inside, so the syntax reads like a list comprehension with square brackets swapped for curly ones.
words = ["apple", "avocado", "banana", "blueberry", "cherry"]
lengths = {len(word) for word in words}
print(sorted(lengths))
first_letters = {word[0] for word in words}
print(sorted(first_letters))
The transformation happens before the uniqueness check, which is the useful part. {word[0] for word in words} is not "the first letters of the unique words" — it is "the unique first letters", because the expression is evaluated for every word and the results are then deduplicated.
Counting is the other common use, and it is where the standard library wins. A Counter does the counting in one line, and it returns zero for keys it has never seen instead of raising.
from collections import Counter
words = ["apple", "avocado", "banana", "blueberry", "cherry"]
counts = Counter(word[0] for word in words)
print(counts.most_common())
manual = {}
for word in words:
manual[word[0]] = manual.get(word[0], 0) + 1
print(manual)
Same numbers, and the Counter version is two lines shorter and gives you most_common() for free. The manual version is worth understanding anyway, because dict.get(key, 0) plus one is the pattern you will meet in code that predates Counter, and in code that has to run on a restricted standard library.
Dict and set recipes
| Goal | Code |
|---|---|
| Map values to keys | {k: f(v) for k, v in d.items()} |
| Filter entries | {k: v for k, v in d.items() if test(v)} |
| Two lists into a dict | {k: v for k, v in zip(keys, values)} |
| Invert a dict | {v: k for k, v in d.items()} |
| Unique values | {f(x) for x in items} |
| Unique values, sorted | sorted({f(x) for x in items}) |
| Count occurrences | Counter(items) |
| Group into lists | defaultdict(list) |
Try it yourself: build a dictionary of five students and their marks, then produce a copy with the keys uppercased, a copy containing only the students who passed, and an inverted copy keyed by mark — checking whether any mark collides. Next, take a list of fruit names and produce a set of their lengths, a set of their first letters, and a Counter of their first letters. Finally, write a nested comprehension that turns a list of lists into a dictionary of row index to row sum, and check it against a plain loop.