DEV Community

Cover image for Python Comprehensions: From Confusing to Crystal Clear in 10 Minutes
Ameer Abdullah
Ameer Abdullah

Posted on

Python Comprehensions: From Confusing to Crystal Clear in 10 Minutes

List comprehensions confuse beginners not because they are complex but because they are written in the opposite order from how most people think about them.

Once you learn to read them in the right order, they become faster to understand than the equivalent for loop.


The Reading Order

Do not read a comprehension left to right. Read it in this order:

  1. The for part first: where do the values come from?
  2. The if part second: which values are included?
  3. The expression first: what happens to each included value?
result = [x * 2 for x in range(10) if x % 3 == 0]
Enter fullscreen mode Exit fullscreen mode

Step 1 (for): x takes values 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Step 2 (if): keep only x where x % 3 == 0: that gives 0, 3, 6, 9
Step 3 (expression): multiply each by 2: 0, 6, 12, 18

Output: [0, 6, 12, 18]


Dictionary Comprehensions Work the Same Way

scores = {"Alice": 85, "Bob": 42, "Carol": 91, "Dave": 67}
passed = {name: score for name, score in scores.items() if score >= 70}
print(passed)
Enter fullscreen mode Exit fullscreen mode

Step 1 (for): name and score take each key-value pair
Step 2 (if): keep only pairs where score is 70 or above
Step 3 (expression): create a new dict with those same pairs

Output: {'Alice': 85, 'Carol': 91, 'Dave': 67}


Set Comprehensions Remove Duplicates Automatically

words = ["hello", "world", "hello", "python", "world", "code"]
unique_lengths = {len(word) for word in words}
print(unique_lengths)
Enter fullscreen mode Exit fullscreen mode

Output: {4, 5, 6} (order may vary, sets are unordered)

"hello" has length 5, "world" has length 5, "python" has length 6, "code" has length 4. The set removes duplicate lengths automatically.


The Nested Comprehension

This is where most people give up, but the reading order works here too.

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
print(flat)
Enter fullscreen mode Exit fullscreen mode

Read the for clauses left to right, outer to inner:

First for: row takes each sublist: [1,2,3], [4,5,6], [7,8,9]
Second for: num takes each element in the current row
Expression: include num as-is

Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]


The Interview Version

pairs = [(x, y) for x in range(3) for y in range(3) if x != y]
print(pairs)
Enter fullscreen mode Exit fullscreen mode

Outer for: x takes 0, 1, 2
Inner for: y takes 0, 1, 2 for each x
If: exclude pairs where x equals y

Pairs where x != y:
(0,1), (0,2), (1,0), (1,2), (2,0), (2,1)

Output: [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]


Generator Expressions: The Memory-Efficient Version

import sys

list_comp = [x**2 for x in range(1000)]
gen_expr  = (x**2 for x in range(1000))

print(sys.getsizeof(list_comp))
print(sys.getsizeof(gen_expr))
Enter fullscreen mode Exit fullscreen mode

Output (approximate):

8856
104
Enter fullscreen mode Exit fullscreen mode

The list comprehension stores all 1000 squared values in memory. The generator expression stores only the recipe for generating them, computing each value on demand. For large sequences, the generator uses a fraction of the memory.

For more comprehension and output prediction practice, visit PyCodeIt.


Top comments (0)