List comprehensions build new lists in one expression: a readable middle ground between a long append loop and heavy functional chains. If you are new to the idea, treat it as shorthand Python already understands—you still picture a for loop, but the language packs “loop + collect” into a single bracketed line. This page walks from syntax through filters, nesting, and when to prefer a plain loop. Examples use print(...) so you can run them locally or with the site Run control where enabled.
Tested on: Python 3.13.3; kernel 6.14.0-37-generic.
For background on lists themselves, see Python lists and list extend. Filtered comprehensions overlap with remove element from list patterns. When you only need a yes/no scan over an iterable, a generator expression with any() or all() avoids building a full list of flags first—see Python any() and all().
What is list comprehension in Python?
A list comprehension is a compact way to build a new list by looping over something you can iterate over (a range, a string, another list, and so on). You always get a fresh list object; the comprehension itself does not “change” the original data unless your expression mutates objects in place—which is usually avoided.
Mental model for beginners:
- Square brackets
[]mean “produce a list.” - Read the
for item in iterablepart as a normal loop header: “for eachitemcoming fromiterable…” - The expression at the left is the value that gets appended for that iteration (after any
iffilter passes).
So [x * 2 for x in range(3)] reads: “make a list of x * 2 for each x in 0, 1, 2,” which yields [0, 2, 4].
Same idea written the long way—many tutorials start here before collapsing to a comprehension:
out = []
for x in range(3):
out.append(x * 2)
comp = [x * 2 for x in range(3)]
print(out == comp)That is all “syntactic sugar” means: fewer lines for the same result when you only need to transform or filter into a list. The form is idiomatic for simple work on lists you copy or build; CPython implements it efficiently, but readability still comes first. The next section names each slot in the bracket so you can match pieces to the examples that follow.
Python list comprehension syntax
Every comprehension has the same skeleton: an expression (what to store), a for clause (where values come from), and optionally an if filter (which iterations count). Python evaluates the for, applies each if, then evaluates the expression for each surviving iteration—always in that order.
Core shapes (read them aloud left to right):
[expression for item in iterable]
[expression for item in iterable if condition]
Per item (a Python conditional expression, not a full if / elif block):
[value_if_true if condition else value_if_false for item in iterable]
print([x * 2 for x in range(5)])Python walks x = 0, 1, 2, 3, 4, evaluates x * 2 each time, and collects [0, 2, 4, 6, 8]—five elements because range(5) yields five values.
List comprehension vs for loop
Both styles allocate a list and fill it from a loop. The explicit loop shows each append; the comprehension hides append but still runs the same number of iterations. Pick the form your teammates can read fastest—often the comprehension for “transform or filter into a list,” often a loop when you need extra logic between iterations.
squares_loop = []
for x in range(5):
squares_loop.append(x ** 2)
squares_comp = [x ** 2 for x in range(5)]
print(squares_loop == squares_comp)squares_loop and squares_comp both end as [0, 1, 4, 9, 16]; print shows True. Performance is usually similar for small, simple work; if you micro-optimize, use timeit on your real data instead of assuming one style always wins.
Basic list comprehension examples
These three patterns cover most day-to-day use: reuse values as-is, change each value, or drop values you do not want. In each case Python walks the source iterable once (unless you nest more loops later) and appends one result per kept iteration.
Create a list from an existing list
Sometimes the expression is just the loop variable: you walk nums and emit one output per input. That is handy for copies, light projections, or pairing with a later filter in the same comprehension.
nums = [1, 2, 3, 4]
doubled = [n * 2 for n in nums]
print(doubled)nums stays [1, 2, 3, 4]. For each n, Python appends n * 2, so doubled becomes [2, 4, 6, 8]—same length as the source list.
Transform each item in a list
When the expression calls a method or function, you are mapping every element through the same operation—like a tiny assembly line.
words = ["a", "b", "c"]
upper = [w.upper() for w in words]
print(upper)Each string w becomes its uppercase form, so the printed list is ['A', 'B', 'C'].
Filter items using if condition
An if at the end skips iterations whose condition is false; nothing is appended for those items, so the new list can be shorter than the iterable.
print([x for x in range(15) if x % 3 == 0])range(15) still visits 0 through 14, but only numbers divisible by 3 are kept, producing [0, 3, 6, 9, 12].
List comprehension with if else condition
Here the if / else sits inside the expression (a conditional expression). Python evaluates it once per loop item to decide which single value to append. That differs from a trailing if, which decides whether to append anything at all.
labels = ["even" if n % 2 == 0 else "odd" for n in range(6)]
print(labels)For n from 0 to 5, even numbers pick "even" and odd pick "odd", so you see ['even', 'odd', 'even', 'odd', 'even', 'odd']. Long chains of else logic are hard to read in one line—prefer a helper function or a normal if / elif loop when the branches multiply.
List comprehension with range()
range is lazy and cheap: it hands out integers one at a time without building a giant list first. Comprehensions pair naturally with range when you care about positions or numeric sequences.
print([i ** 2 for i in range(1, 6)])range(1, 6) yields 1 through 5; each is squared, so the printed list is [1, 4, 9, 16, 25].
List comprehension with strings
A string is iterable over its characters. Splitting on spaces gives words, which you can normalize in one pass.
s = "hello"
codes = [ord(c) for c in s]
print(codes)Each character becomes its Unicode code point: h→104, e→101, and so on, so you get [104, 101, 108, 108, 111].
sentence = "list comprehension in python"
print([w.capitalize() for w in sentence.split()])split() makes ['list', 'comprehension', 'in', 'python']; capitalize() title-cases each word, yielding ['List', 'Comprehension', 'In', 'Python'].
List comprehension with list of lists
Create a list of lists
You need one inner comprehension per outer row so each row is a new list object. Reusing one inner list by mistake would make every row alias the same list.
rows = 3
cols = 4
matrix = [[0 for _ in range(cols)] for _ in range(rows)]
print(matrix)The outer _ runs three times; each time the inner list builds four zeros. Output is three separate rows: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]].
Flatten a list of lists
Write the for clauses in the same order you would nest them in regular code: outer iterable first, inner next. That keeps the reading order aligned with “for each group, for each item in the group.”
nested = [[1, 2], [3], [4, 5, 6]]
flat = [x for group in nested for x in group]
print(flat)Python walks [1, 2], then [3], then [4, 5, 6], emitting each x in order, so flat becomes [1, 2, 3, 4, 5, 6].
Nested list comprehension in Python
Here the outer comprehension builds rows, and the inner one fills each row using the outer variable (i). That is how you generate tables from index math without manual append loops.
table = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(table)For i = 1, inner j is 1,2,3 → [1, 2, 3]. For i = 2 → [2, 4, 6]. For i = 3 → [3, 6, 9]. The printed value is a three-by-three multiplication table as nested lists.
Multiple for loops in list comprehension
Chaining for clauses is the same as nesting loops: the rightmost for changes fastest. Use this when you need the Cartesian product of two ranges, pairs from two sources, or flattening patterns that do not fit a single iterable.
pairs = [(i, j) for i in range(2) for j in range(3)]
print(pairs)i is 0, then 1. For each i, j runs 0,1,2, so tuples appear in nested-loop order: [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)].
List comprehension vs map and filter
map applies a function to every item; filter keeps items where a predicate is true. List comprehensions express the same ideas with Python’s for / if syntax, which many teams find easier to scan. lambda is still useful when you already pass a small function into map or filter.
nums = [1, 2, 3, 4, 5]
evens_lc = [n for n in nums if n % 2 == 0]
evens_mf = list(filter(lambda n: n % 2 == 0, nums))
squares_lc = [n * n for n in nums]
squares_mf = list(map(lambda n: n * n, nums))
print(evens_lc == evens_mf, squares_lc == squares_mf)Both even-list forms yield [2, 4]; both square forms yield [1, 4, 9, 16, 25], so print shows True True.
When not to use list comprehension
Comprehensions excel at “compute a list result.” They are the wrong tool when the loop body does more than emit one value per iteration.
- Side effects first: if you need to print, write files, or mutate shared objects while iterating, use a normal
forloop so ordering and debugging stay obvious. - Control flow:
break,continue, or per-iterationtry/exceptdo not fit cleanly inside a comprehension—use a loop. - Heavy branching: many
if/elifpaths or giant ternaries belong in a named function or explicit blocks. - No list needed: if you only consume values once, prefer a generator expression
( ... )or a plain loop; building a list you throw away wastes memory.
Common mistakes in Python list comprehension
- Shared inner lists: writing
[inner] * nor reusing one appended list makes every row point at the same object. Build[expr for ...]inside the outer loop so each row is fresh (see the matrix example). - Deep nesting: more than two comprehension levels or long conditional expressions stop reading like prose—split into steps or helper functions.
- Shadowing names: using
list,str, ordictas the loop variable hides builtins and confuses reviewers. - Looking for
elif: the comprehension grammar is not a fullifstatement; emulate complex branching with functions or loops instead of nested ternaries.
Python list comprehension quick reference table
Use this table as a cheat sheet: match your intent to the pattern, then plug in your real expression and iterables.
| Pattern | Example |
|---|---|
| Map | [f(x) for x in items] |
| Filter | [x for x in items if cond(x)] |
| Map + filter | [f(x) for x in items if cond(x)] |
| Ternary per item | [a if c else b for x in items] |
| Nested builders | [[inner for inner in row] for row in data] |
| Flatten one level | [x for row in data for x in row] |
Summary
List comprehensions combine an expression, one or more for clauses, and optional if filters to build lists concisely. They mirror simple for loops and can replace many map/filter patterns with clearer local style. Nested forms help with matrices and flattening, but deep nesting hurts readability—switch to loops or small functions when the comprehension stops scanning like English. The sections above walk through what each clause does and what the printed lists mean; for language rules, see the official tutorial on list comprehensions.

