Python Lesson 22 – Dictionary Comprehensions | Dataplexa

Dictionary Comprehensions

You already know that list comprehensions let you build lists in a single expressive line. Python applies the same idea to dictionaries — dictionary comprehensions let you create, transform, and filter dictionaries without writing a loop, manually creating an empty dict, and assigning keys one by one.

Dictionary comprehensions are used heavily in data transformation, API response processing, and configuration building. This lesson covers every pattern you will encounter in real Python codebases.

The Problem Dictionary Comprehensions Solve

Suppose you have a list of words and you want to build a dictionary that maps each word to its length. The traditional loop approach works but requires several lines of setup:

# Traditional loop — building a dict step by step

words = ["apple", "banana", "cherry"]
lengths = {}                          # start with an empty dict

for w in words:
    lengths[w] = len(w)               # assign each key → value manually

print(lengths)
{'apple': 5, 'banana': 6, 'cherry': 6}

A dictionary comprehension replaces all of this with a single readable line that expresses the same intent directly.

Basic Syntax

The structure mirrors list comprehensions exactly — except you use curly braces and provide both a key expression and a value expression separated by a colon.

Why it exists: transforming a collection into a dictionary is one of the most common data-wrangling tasks in Python. Comprehensions let you do it without boilerplate.

Real-world use: a web API returns a list of user records and you need a dictionary keyed by user ID for fast lookups — a dict comprehension builds it in one line.

# Basic dictionary comprehension

words = ["apple", "banana", "cherry"]

# Map each word to its character length
lengths = {w: len(w) for w in words}
print(lengths)

# Map numbers to their squares
squares = {n: n ** 2 for n in range(1, 6)}
print(squares)
{'apple': 5, 'banana': 6, 'cherry': 6}
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
  • Structure: {key_expr: value_expr for item in iterable}
  • Curly braces {} make it a dict — square brackets [] make it a list
  • Both the key and value expressions are evaluated for every item in the iterable
  • Keys must be hashable — strings, numbers, and tuples work; lists do not

Transforming an Existing Dictionary

You can iterate directly over an existing dictionary using .items(), which yields key-value pairs. This lets you transform keys, values, or both in one expression.

Why it exists: it is very common to need a modified copy of a dictionary — uppercased keys, rounded values, currency-formatted prices — without touching the original.

Real-world use: a pricing engine takes a dictionary of raw product costs and applies a markup to every value, producing a new dictionary of retail prices.

# Transforming keys and values from an existing dict

costs = {"shirt": 12.00, "hat": 8.50, "bag": 22.00}

# Apply a 40% markup to every price
retail = {item: round(price * 1.40, 2) for item, price in costs.items()}
print(retail)

# Uppercase all keys
upper_keys = {k.upper(): v for k, v in costs.items()}
print(upper_keys)
{'shirt': 16.8, 'hat': 11.9, 'bag': 30.8}
{'SHIRT': 12.0, 'HAT': 8.5, 'BAG': 22.0}
  • dict.items() returns pairs of (key, value) — unpack them directly in the for clause
  • The original dictionary is never modified — a new one is always produced
  • You can transform the key, the value, or both in the same comprehension

Filtering with an if Clause

Just like list comprehensions, you can add an if condition to include only key-value pairs that meet a certain test.

Why it exists: you often need a subset of a dictionary — only active users, only items in stock, only scores above a threshold. The filter keeps the comprehension clean and one-line.

Real-world use: a dashboard filters a dictionary of product inventory to show only items where stock is greater than zero.

# Filtering a dictionary with an if clause

scores = {"Alice": 88, "Bob": 53, "Carol": 76, "Dave": 45, "Eve": 92}

# Keep only students who passed (score >= 60)
passed = {name: score for name, score in scores.items() if score >= 60}
print(passed)

# Keep only items priced under $15
inventory = {"pen": 1.50, "notebook": 4.99, "desk": 89.99, "lamp": 24.99}
affordable = {item: price for item, price in inventory.items() if price < 15}
print(affordable)
{'Alice': 88, 'Carol': 76, 'Eve': 92}
{'pen': 1.5, 'notebook': 4.99}
  • Structure with filter: {k: v for k, v in d.items() if condition}
  • Pairs where the condition is False are excluded from the new dictionary entirely
  • You can filter on the key, the value, or a combination of both

Building a Dictionary from Two Lists

A very common pattern is combining two parallel lists — one of keys and one of values — into a single dictionary using zip().

Why it exists: data often arrives as separate parallel sequences. zip() pairs them up, and a dict comprehension turns those pairs into a lookup table instantly.

Real-world use: a CSV file has a separate header row and a data row — zip them together in a dict comprehension to get a named record in one line.

# Combining two lists into a dictionary with zip()

products = ["coffee", "tea", "juice"]
prices   = [3.50, 2.00, 4.25]

# Pair each product with its price
menu = {item: price for item, price in zip(products, prices)}
print(menu)

# Plain dict(zip()) shown for comparison — no transformation needed here
menu2 = dict(zip(products, prices))
print(menu2)
{'coffee': 3.5, 'tea': 2.0, 'juice': 4.25}
{'coffee': 3.5, 'tea': 2.0, 'juice': 4.25}
  • zip() pairs elements at the same index from two iterables
  • If the lists are different lengths, zip() stops at the shorter one
  • Use the comprehension form when you need to transform keys or values while building
  • For a plain zip-to-dict with no transformation, dict(zip(a, b)) is equally clean

Swapping Keys and Values

Dictionary comprehensions make it trivial to invert a dictionary — turning keys into values and values into keys — which is useful for reverse lookups.

# Inverting a dictionary — swap keys and values

country_code = {"US": "United States", "CA": "Canada", "MX": "Mexico"}

# Build a reverse lookup: full name → abbreviation
code_country = {v: k for k, v in country_code.items()}
print(code_country)
{'United States': 'US', 'Canada': 'CA', 'Mexico': 'MX'}
  • Swap by writing {v: k for k, v in d.items()}
  • This only works correctly when all values in the original dict are unique and hashable
  • If two keys share the same value, only the last one survives in the inverted dict

Conditional Value Assignment

You can use an inline if/else in the value expression to assign different values based on a condition — similar to the ternary pattern in list comprehensions.

# Ternary value assignment in a dict comprehension

scores = {"Alice": 88, "Bob": 53, "Carol": 76, "Dave": 45}

# Label each student as "pass" or "fail"
results = {name: "pass" if score >= 60 else "fail"
           for name, score in scores.items()}
print(results)
{'Alice': 'pass', 'Bob': 'fail', 'Carol': 'pass', 'Dave': 'fail'}
  • Every key is included — the ternary only affects which value is assigned, not membership
  • This is different from a trailing if, which removes pairs entirely
  • Keep the value expression readable — move complex logic to a helper function if needed

Nested Dictionary Comprehensions

You can use a dict comprehension as the value expression inside another dict comprehension to build nested dictionaries in a single statement.

# Nested dict comprehension — building a grade table

students = ["Alice", "Bob"]
subjects = ["math", "science"]

# Build: student → subject → default score of 0
grade_table = {s: {sub: 0 for sub in subjects} for s in students}
print(grade_table)
{'Alice': {'math': 0, 'science': 0}, 'Bob': {'math': 0, 'science': 0}}
  • The inner comprehension runs fresh for every iteration of the outer one
  • Each student gets their own independent inner dictionary — not shared references
  • Beyond one level of nesting, a regular loop is usually clearer to read and debug

Summary Table

Pattern Syntax What It Does
Basic {k: v for x in iterable} Build a dict from any iterable
From dict {k: v for k, v in d.items()} Transform an existing dictionary
Filter {k: v for k, v in d.items() if cond} Keep only matching pairs
From two lists {k: v for k, v in zip(a, b)} Combine parallel lists into a dict
Invert {v: k for k, v in d.items()} Swap keys and values
Ternary value {k: a if cond else b for ...} Assign different values by condition

Practice Questions

Practice 1. What punctuation marks a dictionary comprehension apart from a list comprehension?



Practice 2. Which dictionary method do you call to iterate over both keys and values at the same time?



Practice 3. What built-in function is used to pair two parallel lists before passing them to a dict comprehension?



Practice 4. Write the comprehension syntax to invert a dictionary called d.



Practice 5. What happens when two keys share the same value in a dictionary that is being inverted?



Quiz

Quiz 1. What is the output of {x: x ** 2 for x in range(1, 4)}?






Quiz 2. Which of the following filters a dictionary to keep only pairs where the value is greater than 10?






Quiz 3. What does {v: k for k, v in {"a": 1, "b": 2}.items()} produce?






Quiz 4. In a dictionary comprehension, which of the following is a valid key type?






Quiz 5. What is the difference between a trailing if and a ternary if/else in a dictionary comprehension?






Next up — Advanced Sets covers unions, intersections, differences, and symmetric differences, and shows you when sets outperform lists for high-speed membership testing.