List comprehensions are Python's most powerful syntactic feature โ and the one most developers underuse. They let you build a new list from any iterable in a single, readable expression. Mastering them doesn't just make your code shorter; it makes it faster (the C-level bytecode is more optimized than an equivalent for loop) and more Pythonic.
Here are 10 patterns, ranging from beginner to production-grade, with before-and-after code so you can see exactly what each one replaces.
Pattern 1: Basic transformation
# Before squares = [] for n in range(10): squares.append(n ** 2) # After โ list comprehension squares = [n ** 2 for n in range(10)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Pattern 2: Filter with condition
evens = [n for n in range(20) if n % 2 == 0] # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] # Filter strings: names longer than 4 characters names = ["Ali", "Raman", "Bob", "Priya", "Sam"] long_names = [n for n in names if len(n) > 4] # ['Raman', 'Priya']
Pattern 3: Transform and filter together
# Email addresses for users who have an @ sign and domain raw_emails = ["raman@codewithraman.com", "invalid", "bob@example.com", ""] valid = [e.lower().strip() for e in raw_emails if "@" in e and "." in e] # ['raman@codewithraman.com', 'bob@example.com']
Pattern 4: Conditional expression (ternary)
scores = [45, 78, 92, 33, 67, 88]
grades = ["Pass" if s >= 50 else "Fail" for s in scores]
# ['Fail', 'Pass', 'Pass', 'Fail', 'Pass', 'Pass']
Pattern 5: Flatten a nested list
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] flat = [n for row in matrix for n in row] # [1, 2, 3, 4, 5, 6, 7, 8, 9] # Order matters: outer loop first, inner loop second # Same as: for row in matrix: for n in row: flat.append(n)
Pattern 6: Extract from dicts
users = [
{"name": "Raman", "age": 28, "active": True},
{"name": "Alice", "age": 34, "active": False},
{"name": "Bob", "age": 22, "active": True},
]
# Get names of active users only
active_names = [u["name"] for u in users if u["active"]]
# ['Raman', 'Bob']
# Build a lookup dict โ dict comprehension
name_to_age = {u["name"]: u["age"] for u in users}
# {'Raman': 28, 'Alice': 34, 'Bob': 22}
Pattern 7: String manipulation
csv_line = " id , name , email , city "
headers = [h.strip().lower() for h in csv_line.split(",")]
# ['id', 'name', 'email', 'city']
# Generate slugs from titles
titles = ["SQL Window Functions", "Python for Data Engineers", "ERWIN Tutorial"]
slugs = [t.lower().replace(" ", "-") for t in titles]
# ['sql-window-functions', 'python-for-data-engineers', 'erwin-tutorial']
Pattern 8: Zip two lists
columns = ["customer_id", "first_name", "email"] values = [101, "Raman", "raman@example.com"] # Build INSERT VALUES clause pairs = [f"{c} = {repr(v)}" for c, v in zip(columns, values)] # ["customer_id = 101", "first_name = 'Raman'", "email = 'raman@example.com'"]
Pattern 9: Set and frozenset comprehensions
tags = ["SQL", "sql", "Python", "PYTHON", "Java", "java"]
unique_lower = {t.lower() for t in tags}
# {'sql', 'python', 'java'} โ set, unordered
Pattern 10: Generator expression (memory efficient)
# List comprehension โ builds entire list in RAM total = sum([n ** 2 for n in range(10_000_000)]) # Generator โ computes on the fly, O(1) memory total = sum(n ** 2 for n in range(10_000_000)) # just drop the []
When NOT to use list comprehensions
- Side effects โ if you need to print, log, or modify external state inside the loop, use
for - Complex logic โ if the body is more than a short expression, extract it into a function and call that
- Error handling โ you can't put a try/except inside a comprehension (use a helper function)
- Three or more nested loops โ extract into a function