**From loop to comprehension**
A list comprehension is a one-line expression that builds a list by transforming and/or filtering an iterable. It replaces a common loop pattern:
```python
# Traditional loop
squares = []
for x in range(10):
squares.append(x ** 2)
# List comprehension — same result
squares = [x ** 2 for x in range(10)]
```
The general structure is:
```
[expression for item in iterable if condition]
^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^
what to where to get it optional filter
produce
```
**Filtering with if**
```python
# Only even squares
even_squares = [x ** 2 for x in range(10) if x % 2 == 0]
# [0, 4, 16, 36, 64]
# Only non-empty strings after stripping
words = [' hello ', '', ' ', 'world']
clean = [w.strip() for w in words if w.strip()]
# ['hello', 'world']
```
**Dict and set comprehensions**
The same syntax works for dicts and sets:
```python
# Dict comprehension
word_lengths = {w: len(w) for w in ['hello', 'world', 'python']}
# {'hello': 5, 'world': 5, 'python': 6}
# Invert a dict (careful: only works if values are unique)
original = {'a': 1, 'b': 2, 'c': 3}
inverted = {v: k for k, v in original.items()}
# {1: 'a', 2: 'b', 3: 'c'}
# Set comprehension — automatically deduplicates
unique_lengths = {len(w) for w in ['hi', 'hello', 'hey', 'world']}
# {2, 5}
```
**Generator expressions**
Replace `[...]` with `(...)` to get a lazy generator — values computed on demand, no intermediate list stored in memory:
```python
# List — builds the whole list upfront
total = sum([x ** 2 for x in range(10_000_000)])
# Generator — computes one value at a time, much less memory
total = sum(x ** 2 for x in range(10_000_000))
# When passing to a function, outer parens can be dropped
```
**The walrus operator `:=` in comprehensions (Python 3.8+)**
Sometimes you compute an intermediate value for both the filter and the output. `:=` (walrus) lets you assign inside an expression:
```python
# Without walrus — compute strip() twice:
clean = [w.strip() for w in words if w.strip()]
# With walrus — compute once, reuse:
clean = [s for w in words if (s := w.strip())]
```
Note: the variable `s` leaks into the enclosing scope after the comprehension — unlike normal comprehension variables, which are scoped to the comprehension itself.
Nested comprehensions, cartesian product, and performance vs loops
**Nested comprehensions**
A nested comprehension has two `for` clauses. The outer loop runs first, the inner loop runs for each outer iteration — same order as nested `for` loops:
```python
# Flatten a 2D matrix
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]
# Equivalent loop:
flat = []
for row in matrix: # outer — first in comprehension
for n in row: # inner — second in comprehension
flat.append(n)
# Cartesian product
pairs = [(x, y) for x in [1, 2, 3] for y in ['a', 'b']]
# [(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')]
```
**Comprehension of comprehensions**
The expression itself can be a comprehension, creating a list of lists:
```python
# Transpose a matrix
matrix = [[1, 2, 3], [4, 5, 6]]
transposed = [[row[i] for row in matrix] for i in range(3)]
# [[1, 4], [2, 5], [3, 6]]
```
**Performance: comprehension vs loop**
List comprehensions are generally faster than equivalent `for` loops in CPython because the list-building bytecode is optimized:
```python
import timeit
# Comprehension
timeit.timeit('[x*2 for x in range(1000)]', number=10000)
# roughly 0.5 s
# Equivalent loop
timeit.timeit(
'result=[]\nfor x in range(1000): result.append(x*2)',
number=10000
)
# roughly 0.8 s — ~60% slower
```
The `map()` function with a simple built-in (no lambda) is the fastest for pure transformation, but the difference is rarely meaningful outside hot loops:
```python
list(map(str, range(1000))) # fastest for single built-in function
[str(x) for x in range(1000)] # almost as fast, more readable
```
When not to use comprehensions: side effects, nesting limits, common mistakes
**When NOT to use comprehensions**
Comprehensions are great for simple, declarative transformations. But they have a readability limit — push past it and a regular loop is better.
**Rule of thumb**: if you can't read it aloud in one breath, use a loop.
```python
# OK — one transformation, one filter
result = [x * 2 for x in items if x > 0]
# Borderline — two filters, one transform
result = [x.strip() for x in lines if x.strip() and not x.startswith('#')]
# Too complex — use a loop:
# (walrus helps but still hard to read)
result = [processed for x in data
if (y := expensive(x)) is not None
if (processed := transform(y)) > threshold]
```
**Never use comprehensions for side effects**
```python
# BAD — comprehension just for the side effect:
[print(x) for x in items] # creates a pointless list of Nones
[db.save(item) for item in items] # same problem
# GOOD — use a loop for side effects:
for x in items:
print(x)
```
**Common comprehension mistakes**
```python
# 1. Forgetting that variables leak with walrus (:=)
clean = [s for w in words if (s := w.strip())]
print(s) # still defined here — might not be what you expect
# 2. Using assignment = instead of comparison == inside filter:
# [x for x in items if x = 0] # SyntaxError — good, Python catches this
# 3. Deep nesting — hard to read:
result = [[cell*2 for cell in row if cell > 0] for row in matrix if sum(row) > 0]
# Much clearer as a function with loops
# 4. Comprehension over a generator that gets exhausted:
gen = (x for x in range(5))
a = [x for x in gen] # [0, 1, 2, 3, 4]
b = [x for x in gen] # [] — generator already exhausted!
```
**Quick decision guide**
```
Situation Use
───────────────────────────────── ──────────────────────────────
Simple transform or filter list/dict/set comprehension
Large dataset, process one at a time generator expression
Side effects (print, save, etc.) for loop
Complex logic / multiple conditions for loop with if/else
Two+ levels of nesting for loops (readability first)
```
def long_words(words, min_length):
return [w for w in words if len(w) > min_length]
result = long_words(["cat", "elephant", "dog", "hippopotamus"], 4)
print(result)
Write a function that takes a list of numbers and returns a new list where positive numbers are kept as-is and negative numbers are replaced with their absolute value.
Write a function that takes a list of numbers and returns the sum of the squares of all numbers greater than zero. Use a generator expression inside sum().
def sum_of_positive_squares(numbers):
return sum(n ** 2 for n in numbers if n > 0)
result = sum_of_positive_squares([1, -2, 3, -4, 5])
print(result)
No split tab
Cookie preferences
We use necessary cookies to run the site. With your permission, we can also save your site preferences and use analytics and advertising cookies to understand usage and support the project.
Open tools in tabs.Exercises, IDE tools, and trainers stay available as site tabs.
Switch without losing context.Move between explanations, code, and utilities while keeping your place.
Use the sidebar as your map.The left panels hold navigation, settings, files, libraries, and tool controls.
PythonJavaScriptSQLite
One IDE, three practical modes
Python in the browser.Run small scripts, try libraries, and practice API requests without installing anything.
JavaScript for quick experiments.Test browser-friendly code and compare ideas next to your learning materials.
SQLite for data practice.Open the database explorer to inspect tables, write queries, and learn SQL workflows locally.
TopicIDE
Work side by side with split tabs
Keep instructions visible.Open an exercise or reference page beside the IDE instead of jumping back and forth.
Compare tools while you learn.Place regex checks, explanations, and code experiments next to each other when the task needs it.
Close the split when you are done.The workspace returns to a single focused tab, and your open site tabs remain available.
Code Typing Trainer
Or plain text
This trainer is designed for a physical keyboard.Open this section on a laptop or desktop with a wide screen. Touch typing practice will not work correctly on a phone.
Speed: 0 chars/min
0 words/min
Best speed (60s): 0 chars/min
0 words/min
Errors: 0
Total time: 0.0 s
To practice touch typing, avoid looking at your physical keyboard.