Dictionary Comprehensions
The same syntax as a list comprehension, with a key and a value separated by a colon. It is the fastest way to build, filter, invert or reshape a mapping.
- The shape
- Building from two sequences
- Building from a single sequence
- Filtering
- Transforming values
- Transforming keys
- Inverting
- Conditional values
- Nested dictionary comprehensions
- Practical examples
- Counting without Counter
- Building a lookup index
- Applying defaults
- Selecting a subset of keys
- Common mistakes
- Best practices
- Practice
- Conclusion
- Basics
- Data Types
- Operators
- Strings
- Control Flow
- Lists
- Tuples
- Sets
- Dictionaries
- Comprehensions
- Functions
- Advanced Functions
- Recursion
- Exception Handling
- File Handling
- Modules
- Standard Library
- OOP
- Advanced OOP
- Iterators and Generators
- Decorators
- Context Managers
- Descriptors and Dataclasses
- Python Internals
- Concurrency
- Regular Expressions
- Serialization
- Command Line Python
- Testing and Debugging
- Type Hints
- Performance
- Python Security
- DSA with Python
The shape
{ key_expression : value_expression for item in iterable if condition }# The loop
squares = {}
for n in range(5):
squares[n] = n * n
# The comprehension
squares = {n: n * n for n in range(5)}
print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}The colon is the only difference from a set comprehension.{n for n in x}is a set;{n: n for n in x}is a dictionary.
Building from two sequences
names = ["Meera", "Arun", "Sara"]
scores = [92, 78, 85]
result = {name: score for name, score in zip(names, scores)}
print(result) # {'Meera': 92, 'Arun': 78, 'Sara': 85}
print(dict(zip(names, scores))) # the same thing, shorter
# With a transformation, where dict(zip(...)) no longer suffices
print({name.lower(): score for name, score in zip(names, scores)})Building from a single sequence
words = ["apple", "banana", "fig"]
print({w: len(w) for w in words}) # {'apple': 5, 'banana': 6, 'fig': 3}
print({w: w.upper() for w in words})
print({w[0]: w for w in words}) # first letter to word; later wins
print({i: w for i, w in enumerate(words)}) # index to wordFiltering
scores = {"Meera": 92, "Arun": 45, "Sara": 78, "Ravi": 30}
passed = {name: score for name, score in scores.items() if score >= 50}
print(passed) # {'Meera': 92, 'Sara': 78}
short_names = {k: v for k, v in scores.items() if len(k) <= 4}
print(short_names) # {'Arun': 45, 'Sara': 78, 'Ravi': 30}
# Filter and transform at once
print({k.upper(): v + 5 for k, v in scores.items() if v < 50})Transforming values
prices = {"pen": 10.5, "book": 250.0, "bag": 899.99}
with_tax = {item: round(price * 1.18, 2) for item, price in prices.items()}
print(with_tax)
as_text = {item: f"Rs {price:,.2f}" for item, price in prices.items()}
print(as_text)
# Clamp every value into a range
clamped = {k: max(0, min(100, v)) for k, v in {"a": 150, "b": -20}.items()}
print(clamped) # {'a': 100, 'b': 0}Transforming keys
raw = {" Name ": "Meera", "AGE": 27, "City ": "Pune"}
cleaned = {key.strip().lower(): value for key, value in raw.items()}
print(cleaned) # {'name': 'Meera', 'age': 27, 'city': 'Pune'}Normalising keys as data comes in is one of the most useful things a dictionary comprehension does, and it is worth doing at the boundary of your program.
Inverting
ages = {"Meera": 27, "Arun": 31}
inverted = {age: name for name, age in ages.items()}
print(inverted) # {27: 'Meera', 31: 'Arun'}ages = {"Meera": 27, "Arun": 31, "Sara": 27}
print({age: name for name, age in ages.items()}) # {27: 'Sara', 31: 'Arun'}Duplicate values collapse, and the last one wins. When that matters, group instead of inverting:
from collections import defaultdict
grouped = defaultdict(list)
for name, age in ages.items():
grouped[age].append(name)
print(dict(grouped)) # {27: ['Meera', 'Sara'], 31: ['Arun']}Conditional values
scores = {"Meera": 92, "Arun": 45}
labels = {name: ("pass" if score >= 50 else "fail") for name, score in scores.items()}
print(labels) # {'Meera': 'pass', 'Arun': 'fail'}
grades = {
name: "A" if s >= 90 else "B" if s >= 75 else "C"
for name, s in {"a": 95, "b": 80, "c": 60}.items()
}
print(grades) # {'a': 'A', 'b': 'B', 'c': 'C'}The second example works, but a chain of conditional expressions is hard to read. A small helper function called from the comprehension is usually better.
Nested dictionary comprehensions
table = {
row: {col: row * col for col in range(1, 4)}
for row in range(1, 4)
}
print(table)
# {1: {1: 1, 2: 2, 3: 3}, 2: {1: 2, 2: 4, 3: 6}, 3: {1: 3, 2: 6, 3: 9}}
print(table[2][3]) # 6people = {
"meera": {"age": 27, "city": "Pune", "temp": 1},
"arun": {"age": 31, "city": "Kochi", "temp": 2},
}
# Drop a field from every nested record
cleaned = {
name: {k: v for k, v in details.items() if k != "temp"}
for name, details in people.items()
}
print(cleaned)Practical examples
Counting without Counter
text = "mississippi"
counts = {ch: text.count(ch) for ch in set(text)}
print(counts) # {'m': 1, 'i': 4, 's': 4, 'p': 2}This is correct but does more work than it looks: count scans the whole string once per distinct character. For a long text, Counter is the right tool.
Building a lookup index
records = [
{"id": 101, "name": "Meera"},
{"id": 102, "name": "Arun"},
]
by_id = {r["id"]: r for r in records}
print(by_id[102]["name"]) # ArunTurning a list of records into a dictionary keyed by id changes lookup from a scan into a direct access. It is one of the highest value comprehensions you will write.
Applying defaults
defaults = {"theme": "light", "size": 12, "wrap": True}
user = {"size": 14}
settings = {key: user.get(key, value) for key, value in defaults.items()}
print(settings) # {'theme': 'light', 'size': 14, 'wrap': True}Selecting a subset of keys
record = {"name": "Meera", "age": 27, "password": "secret", "token": "abc"}
public_fields = {"name", "age"}
safe = {k: v for k, v in record.items() if k in public_fields}
print(safe) # {'name': 'Meera', 'age': 27}Common mistakes
- Forgetting the colon and building a set instead.
- Iterating a dictionary directly and getting only keys; use
.items(). - Inverting a dictionary with duplicate values and silently losing entries.
- Producing duplicate keys from a transformation, so earlier entries disappear.
- Nesting conditional expressions until the line is unreadable.
- Using
{k: expensive(k) for k in items}whereexpensiverescans the data each time.
Best practices
- Use
.items()whenever both key and value are needed. - Normalise keys as data enters your program.
- Build an id keyed index once instead of scanning a list repeatedly.
- Call a named helper from the comprehension rather than embedding a conditional chain.
- Group with
defaultdictwhen inverting could collide.
Practice
- Build a dictionary mapping each word in a sentence to its length, excluding words under four characters.
- Invert a dictionary safely so that duplicate values collect a list of keys.
- Turn a list of product records into a dictionary keyed by product code.
- Apply user overrides on top of defaults without losing any default key.
- Build a nested multiplication table from 1 to 5 and look up a single cell.
Conclusion
A dictionary comprehension is the shortest path between a sequence and a mapping. Use it to build indexes, normalise keys, filter records and apply defaults - and reach for defaultdict the moment two items could produce the same key.