List Comprehensions: Python's Superpower
[name for name in names if name.strip()] within the first screen. They are also faster than the equivalent for-loop, because Python has less work to do behind the scenes.After this lesson, you will be able to:
- Convert a for loop that builds a list into a one-line list comprehension
- Filter items using the 'if condition' part of a comprehension
- Write dict and set comprehensions for key-value and unique-value transformations
- Recognize when NOT to use comprehensions (when readability suffers)
Before You Start
#The Problem Comprehensions Solve
You often write for loops just to build a new list:
# The verbose way — 4 lines to do one thing
squares = []
for x in range(10):
squares.append(x ** 2)
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]Python has a one-line way to express this:
# The Pythonic way — 1 line, same result
squares = [x ** 2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]What does [x * 2 for x in range(4)] produce?
#See it run: the conveyor belt
x flowing left-to-right: pointer lands on the input, the filter gate drops failing items (red ✗) or lets passers through (green ✓), the transform bubble converts the value, and survivors land in the output on the right. Side-by-side, the equivalent for-loop highlights the matching line at every step, so you can see the line result.append(x*2) light up the moment an item flies into the output list. Six presets cover the full vocabulary: filter+transform, tuples, strings, nested cartesian, set dedup, and dict comprehensions.#The 3 Forms
#Form 1: Basic (no filter)
# [expression for item in iterable]
names = ["alice", "bob", "charlie"]
upper = [name.upper() for name in names]
# ["ALICE", "BOB", "CHARLIE"]
lengths = [len(name) for name in names]
# [5, 3, 7]
doubled = [x * 2 for x in [1, 2, 3, 4, 5]]
# [2, 4, 6, 8, 10]Hit aNameErrorinside a comprehension? Typos in the iterable name or the loop variable are the usual cause ([n for nme in names]raisesNameError: name 'nme' is not definedwhen used). See the error decoder.
#Form 2: With a filter condition
# [expression for item in iterable if condition]
numbers = range(20)
evens = [x for x in numbers if x % 2 == 0]
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
long_names = [name for name in names if len(name) > 4]
# ["alice", "charlie"]
positive_nums = [x for x in [-3, -1, 0, 2, 5, -2, 8] if x > 0]
# [2, 5, 8]What does [x ** 2 for x in [1, 2, 3, 4] if x % 2 == 0] produce?
Which comprehension keeps only the even numbers from `[1, 2, 3, 4]`?
#Form 3: Transformation + filter together
# Square only the even numbers
even_squares = [x ** 2 for x in range(10) if x % 2 == 0]
# [0, 4, 16, 36, 64]
# Clean text — lowercase and strip spaces, skip empty strings
raw = [" Hello ", "WORLD", "", " Python ", ""]
clean = [s.lower().strip() for s in raw if s.strip()]
# ["hello", "world", "python"]#Dict Comprehensions
Same pattern, but creates a dictionary instead of a list:
# {key: value for item in iterable}
words = ["apple", "banana", "cherry"]
word_lengths = {word: len(word) for word in words}
# {"apple": 5, "banana": 6, "cherry": 6}
# Flip a dictionary (swap keys and values)
original = {"a": 1, "b": 2, "c": 3}
flipped = {v: k for k, v in original.items()}
# {1: "a", 2: "b", 3: "c"}
# Square numbers 1-5 as a lookup dict
squares_dict = {x: x**2 for x in range(1, 6)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}What does `{n: n*10 for n in [1, 2, 3]}` produce?
What is the type of result? result = {x for x in [1, 2, 2, 3, 3, 3]}
#Set Comprehensions
Creates a set — unique values only:
# {expression for item in iterable}
words = ["apple", "banana", "apple", "cherry", "banana"]
unique_lengths = {len(word) for word in words}
# {5, 6} — only unique lengths (apple=5, banana=6, cherry=6)
# All unique first letters
first_letters = {word[0] for word in words}
# {"a", "b", "c"}#Comprehensions on Real Data
import os
# Load all .csv files from a directory
csv_files = [f for f in os.listdir("data/") if f.endswith(".csv")]
# Normalize a list of values to 0–1 range
raw_scores = [45, 78, 23, 91, 56]
min_s, max_s = min(raw_scores), max(raw_scores)
normalized = [(x - min_s) / (max_s - min_s) for x in raw_scores]
# Keep only the survey answers that were filled in
responses = [{"name": "Asha", "rating": 5}, {"name": "Ben", "rating": None}]
valid = [r for r in responses if r["rating"] is not None]
# Extract just the ratings
ratings = [r["rating"] for r in valid]#When NOT to Use Comprehensions
Comprehensions shine when the logic is simple. When it gets complex, a for loop is better:
# ❌ Too hard to read — nested comprehension
matrix = [[1 if row == col else 0 for col in range(3)] for row in range(3)]
# ✅ Clearer with a for loop
matrix = []
for row in range(3):
matrix.append([1 if row == col else 0 for col in range(3)])
# Rule of thumb: if you can't read the comprehension in 5 seconds, use a loopInteractive Lab
Practice working with lists and transformations interactively
Key Takeaways
- [x**2 for x in range(10)] — basic comprehension, transforms every item
- [x for x in items if condition] — add 'if' at the end to filter items out
- {word: len(word) for word in words} — dict comprehension creates key-value pairs
- If the comprehension takes more than 5 seconds to understand, use a for loop — readability beats cleverness
What does [x for x in range(10) if x % 3 == 0] produce?
This comprehension is supposed to keep only the even numbers, but it crashes with a SyntaxError. Fix the condition.
[2, 4, 6, 8]
Filter and transform a list of grades
You are given a list of (name, grade) tuples. Write a function `passing(grades)` that returns a list of (name, grade) for every student whose grade is at least 60. Use a single list comprehension.
>>> passing([("Alice", 92), ("Bob", 45), ("Cara", 78), ("Dan", 59)])
[('Alice', 92), ('Cara', 78)]def passing(grades):
# TODO: return [(name, grade), ...] for students with grade >= 60
pass
print(passing([("Alice", 92), ("Bob", 45), ("Cara", 78), ("Dan", 59)]))