Dict & Set Comprehensions
Extend the power of declarative logic to Hash Maps and Sets. Plus, learn the "Missing Link" of Python iteration: The Generator Expression.
Once you master list comprehensions, you unlock the ability to construct any collection type in Python using the same elegant syntax.
However, the most powerful feature in this family isn't a collection at the all. It's the Generator Expression. It allows you to process lazy, infinite streams of data with zero memory overhead, using the exact same syntax you just learned.
Dictionary Comprehensions
This is the cleanest way to transform data into a lookup table. The syntax is similar to a list comprehension, but you specify a key: value pair.
users = [
("Alice", 25, "Engineer"),
("Bob", 30, "Manager"),
("Charlie", 22, "Intern")
]
# Create a lookup table (Name -> Job)
user_jobs = {name: job for name, age, job in users}
# Output: {'Alice': 'Engineer', 'Bob': 'Manager', 'Charlie': 'Intern'}
# Use it for O(1) lookups
print(user_jobs["Alice"]) # 'Engineer'Common Pattern: Reversing a Dictionary
Interviews often ask you to swap keys and values.
original = {'A': 1, 'B': 2, 'C': 3}
# Warning: If multiple keys have the same value, data will be lost!
reversed_dict = {v: k for k, v in original.items()}
# Output: {1: 'A', 2: 'B', 3: 'C'}Set Comprehensions
Set comprehensions look identical to Dictionary comprehensions, but without the colon. They are perfect for gathering unique attributes from a list of objects.
tags = ["python", "javascript", "PYTHON", "Go", "javascript"]
# Normalize and deduplicate in one step
unique_tags = {t.lower() for t in tags}
# Output: {'python', 'javascript', 'go'} (Order is not guaranteed)The Crown Jewel: Generator Expressions
This is arguably more important than list comprehensions. If you replace the square brackets [] with parentheses (), you do NOT get a tuple. (Tuples are immutable; you can't construct them dynamically like this).
Instead, you create a Generator Object.
Eager (List) vs Lazy (Generator)
| Feature | List Component `[]` | Generator Expression `()` |
|---|---|---|
| Result | A complete list in RAM. | An iterator object (Recipe). |
| Memory | Linearly proportional to size (~8MB for 1M ints). | Constant (~120 bytes). |
| Speed | Fast, but pauses program to build entire list. | Instant startup. Calculates items one by one. |
import sys
# 1. List Comprehension (Eager)
# Creates 1 million items in memory immediately
list_comp = [x*2 for x in range(1000000)]
print(sys.getsizeof(list_comp))
# Output: ~8,448,728 bytes (8 MB)
# 2. Generator Expression (Lazy)
# No items created yet. Just the "formula".
gen_exp = (x*2 for x in range(1000000))
print(sys.getsizeof(gen_exp))
# Output: ~128 bytes (Tiny!)
# How to use the generator? Loop over it!
# for num in gen_exp: ...When to use Generators?
You should default to using Generators unless you actually need a list.
- Use Lists if: You need to access indices (`data[4]`), strict length (`len(data)`), or iterate multiple times.
- Use Generators if: You are just looping over the data once (e.g., `sum()`, `max()`, `any()`, `all()`, or a `for` loop).
The "Syntactic Sugar" for Functions
If you pass a generator expression as the only argument to a function, you can omit the parentheses.
numbers = [1, 5, 10, 20]
# ⌠Double Parentheses (Redundant)
total = sum((x*x for x in numbers))
# ✅ Implicit Parentheses (Clean)
total = sum(x*x for x in numbers)
# Check if ANY number is negative
is_neg = any(n < 0 for n in numbers)Common Pitfalls
⌠The "Missing" Tuple Comprehension
The Trap: Beginners often try `tuple(x for x in range(3))` thinking it's special syntax.
The Reality: It's just a Generator Expression passed to the `tuple()` constructor. It works, but it runs the generator to exhaustion and builds a tuple.
⌠Modifying the Source while Iterating
The Trap: Just like loops, do not modify the dictionary/set you are iterating over inside the comprehension.
# ⌠RuntimeError: dictionary changed size during iteration
data = {1: 'a', 2: 'b'}
new = {k: v for k, v in data.items() if data.pop(k)} # DANGER!