Python Dictionary Comprehensions: Build Dicts in One Line Without Sacrificing Clarity
Dictionary comprehensions let you construct dictionaries from any iterable in a single expression. Like list comprehensions, they’re faster to write and often faster to read than the equivalent loop — provided you keep the logic simple.
Basic Syntax
{key_expression: value_expression for item in iterable}The key difference from a list comprehension: you provide two expressions separated by a colon, which become the key and value of each entry in the new dict.
Building a Dictionary from a List
The most common case: take a list and create a dictionary mapping each element to something derived from it.
# Map words to their lengthswords = ["Python", "is", "readable", "and", "fast"]lengths = {word: len(word) for word in words}print(lengths)# {'Python': 6, 'is': 2, 'readable': 8, 'and': 3, 'fast': 4}
# Map numbers to their squaresnumbers = range(1, 6)squares = {n: n**2 for n in numbers}# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}The loop equivalent for context:
squares = {}for n in range(1, 6): squares[n] = n**2Building from Two Lists
zip() pairs up two lists element by element, which maps directly to key-value pairs:
countries = ["Germany", "Japan", "Brazil"]capitals = ["Berlin", "Tokyo", "Brasília"]
capital_of = {country: capital for country, capital in zip(countries, capitals)}print(capital_of)# {'Germany': 'Berlin', 'Japan': 'Tokyo', 'Brazil': 'Brasília'}This is a clean replacement for dict(zip(countries, capitals)) when you want to transform the keys or values before storing them.
Filtering with Conditions
Add an if clause at the end to skip items that don’t meet a condition:
scores = {"Alice": 92, "Bob": 61, "Charlie": 78, "Diana": 45, "Eve": 88}
# Keep only passing scorespassing = {name: score for name, score in scores.items() if score >= 70}print(passing)# {'Alice': 92, 'Charlie': 78, 'Eve': 88}
# Filter a product list by availabilityproducts = { "Widget": {"price": 9.99, "stock": 5}, "Gadget": {"price": 24.99, "stock": 0}, "Doohickey": {"price": 4.99, "stock": 12},}available = {name: info for name, info in products.items() if info["stock"] > 0}Transforming Keys and Values
Comprehensions let you modify both the keys and values as you build the new dict:
# Uppercase all keysconfig = {"debug": True, "host": "localhost", "port": 8080}upper_config = {k.upper(): v for k, v in config.items()}# {'DEBUG': True, 'HOST': 'localhost', 'PORT': 8080}
# Apply a function to all valuesprices = {"apple": 1.20, "banana": 0.50, "cherry": 3.00}discounted = {item: round(price * 0.9, 2) for item, price in prices.items()}# {'apple': 1.08, 'banana': 0.45, 'cherry': 2.7}Inverting a Dictionary
When values are unique, you can swap keys and values:
abbreviations = {"US": "United States", "UK": "United Kingdom", "AU": "Australia"}full_name_to_code = {full: code for code, full in abbreviations.items()}# {'United States': 'US', 'United Kingdom': 'UK', 'Australia': 'AU'}This only works reliably when values are unique. If multiple keys share a value, only the last one survives in the inverted dict.
Conditional Expressions in Values
You can use a ternary expression in the value part:
raw_data = {"temperature": "22.5", "pressure": None, "humidity": "65"}
# Convert numeric strings, keep None as Noneprocessed = { k: float(v) if v is not None else None for k, v in raw_data.items()}# {'temperature': 22.5, 'pressure': None, 'humidity': 65.0}Nested Dict Comprehensions
Comprehensions can produce nested dictionaries, though readability degrades quickly with depth:
# Build a multiplication table as a nested dicttable = {i: {j: i * j for j in range(1, 6)} for i in range(1, 6)}print(table[3][4]) # 12
# Accessible, but getting hard to readFor anything beyond one level of nesting, consider using a regular loop:
table = {}for i in range(1, 6): table[i] = {j: i * j for j in range(1, 6)}The inner comprehension is still clear; the outer loop makes the structure explicit.
Grouping Data
One common pattern is grouping a list of records by some attribute:
employees = [ {"name": "Alice", "dept": "Engineering"}, {"name": "Bob", "dept": "Marketing"}, {"name": "Charlie", "dept": "Engineering"}, {"name": "Diana", "dept": "Marketing"},]
# Dict comprehension doesn't directly support grouping — use defaultdict insteadfrom collections import defaultdictby_dept = defaultdict(list)for emp in employees: by_dept[emp["dept"]].append(emp["name"])# {'Engineering': ['Alice', 'Charlie'], 'Marketing': ['Bob', 'Diana']}A dict comprehension isn’t the right tool for grouping (you’d lose all but the last record per key). Use defaultdict or itertools.groupby for that.
When Not to Use a Dict Comprehension
When the logic is complex. If you need multiple conditions, nested logic, or intermediate variables, a loop is clearer:
# Too dense — hard to review or debugresult = {k: transform(v) for k, v in data.items() if complex_check(k) and v is not None}
# Better as a loopresult = {}for k, v in data.items(): if v is None: continue if not complex_check(k): continue result[k] = transform(v)When you need to handle errors per-key. You can’t put a try/except inside a comprehension. Use a loop.
When grouping or accumulating. A comprehension produces one value per key, not a list per key. Use defaultdict for multi-value grouping.
The best dict comprehensions are short and tell you their purpose at a glance. If you find yourself explaining the comprehension to make it understandable, it’s time to expand it into a loop.