List Comprehensions#
Learning Objectives
Questions:
How can I write lists more concisely in Python?
How do list comprehensions compare to regular for loops?
Objectives:
Understand the basic syntax of a list comprehension.
Transform a simple
for
loop into an equivalent list comprehension.Apply conditional filtering within a list comprehension.
What are list comprehensions?#
In Python, a list comprehension is a compact way to build a new list from existing data.
Instead of writing a multi-line for
loop and calling .append()
for each element, you can express the same idea in a single, readable line.
List comprehensions can make your programs shorter, easier to read, and sometimes faster.
But remember: clarity beats cleverness. If a comprehension starts to feel crowded or hard to read, use a regular loop.
Start from a for loop#
Because you already know for
loops, let us begin there and then convert to a list comprehension.
Imagine you want to create a list of squares for the numbers 0 through 9:
squares = []
for x in range(10):
squares.append(x**2)
squares
The comprehension version would look like this (same result):
squares = [x**2 for x in range(10)]
squares
Both approaches do the same thing: iterate → transform → collect.
The comprehension just expresses it more compactly.
The syntax of a list comprehension#
The general pattern of a list comprehension looks like this:
[ expression for item in iterable if condition ]
expression → what you put into the new list (often a transformation of
item
).for item in iterable → the loop that goes through each
item
in your source data.if condition (optional) → a filter deciding whether to include the current
item
.
Think of a list comprehension as a compressed for
loop with an optional filter.
Reading and writing comprehensions step by step#
Start with the loop you would normally write, then compress it:
Write the loop that visits each element.
(Optional) Add a condition to filter elements.
Move the “result expression” (what you would
.append()
) to the front.
Loop → comprehension (even squares 0–9):
# loop
even_squares = []
for x in range(10):
if x % 2 == 0:
even_squares.append(x**2)
even_squares
# comprehension
even_squares = [x**2 for x in range(10) if x % 2 == 0]
even_squares
The two code blocks above do exactly the same thing: they both build a list of the squares of the even numbers from 0 to 9.
In the loop version, we create an empty list, loop over numbers, check if each number is even, and then append its square to the list.
In the comprehension version, the same logic is expressed in a single line: iterate through the numbers, filter with
if x % 2 == 0
, and apply the expressionx**2
.
The comprehension is simply a more compact way to write the loop.
Understanding the order of execution in list comprehensions#
Although the code is written as:
[x**2 for x in range(10) if x % 2 == 0]
The way it executes mirrors a normal for
loop:
Loop through numbers
0
to9
(for x in range(10)
).Check the condition
if x % 2 == 0
- keep only the even numbers.Apply the expression
x**2
to each number that passed the test.
So even though the expression appears first in the code, the execution order is: loop → condition → expression.
Tip: If the order feels confusing, rewrite the comprehension as a loop with .append()
and compare - they are equivalent.
Examples#
Transforming values#
A comprehension can transform each element on the way in:
words = ["python", "list", "comprehension"]
uppercased = [w.upper() for w in words]
uppercased
Filtering elements#
You can include only certain items by adding an if
clause:
evens = [n for n in range(10) if n % 2 == 0]
evens
Combine transform + filter:
even_squares = [n**2 for n in range(10) if n % 2 == 0]
even_squares
Nested comprehensions (use with care)#
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
flattened
Nested comprehensions can be harder to read. If a comprehension feels hard to read, it is often better to write a regular loop.
Practical Tips and Pitfalls
Readability first: If a comprehension is long or has multiple conditions, a regular loop is clearer.
Memory: List comprehensions build the whole list in memory. For very large data, consider a generator expression:
squares_gen = (x**2 for x in range(1_000_000)) # parentheses → generator
- Generators produce items one by one (memory-friendly) but can be iterated only once.
Variable scope: In modern Python, the loop variable inside a comprehension (e.g.,
x
) does not “leak” to the outer scope.Avoid side effects: A list comprehension should mainly be used to build a new list. Try to keep it simple: take some input → transform it → get output.
If you put other actions inside (likeprint()
, writing to a file, or changing variables), the comprehension becomes confusing. These actions are called side effects.
Exercises#
Exercise 1: Odd numbers#
Create a list of the first 20 odd numbers using a list comprehension.
Solution
odds = [2*n + 1 for n in range(20)]
# n values: [0, 1, 2, ..., 19]
# odds list: [1, 3, 5, 7, ..., 39]
We iterate over indices 0..19
and map each n
to the odd number 2*n + 1
. This yields exactly 20 values, starting at 1 and ending at 39.
Exercise 2: Normalise names#
Given names = ["alice", "Bob", "CHARLIE"]
, use list comprehension to build a new list where all names are lowercase.
Solution
names = ["alice", "Bob", "CHARLIE"]
lowers = [name.lower() for name in names]
# lowers list: ['alice', 'bob', 'charlie']
Apply the transformation name.lower()
to each element and collect the results.
Exercise 3: Filter positives#
From numbers = [3, -1, 4, -2, 5, -6]
, use list comprehension to make a list containing only the positive values.
Solution
numbers = [3, -1, 4, -2, 5, -6]
positives = [x for x in numbers if x > 0]
# positives list: [3, 4, 5]
The if x > 0
clause filters out non-positive numbers; the comprehension collects only values that satisfy the condition.
Exercise 4: Filter and transform#
Use list comprehension to produce the squares of all numbers from 0–30 that are divisible by 3.
Solution
squares_div3 = [x**2 for x in range(31) if x % 3 == 0]
# squares_div3 list: [0, 9, 36, 81, 144, 225, 324, 441, 576, 729, 900]
We loop x
over 0..30
, keep only x % 3 == 0
, then apply the expression x**2
to each kept value.
Exercise 5: Two-letter combinations#
Use list comprehension to create all two-letter combinations from "AB"
and "CD"
to get ["AC", "AD", "BC", "BD"]
.
Solution
combos = [a + b for a in "AB" for b in "CD"]
# combos list: ['AC', 'AD', 'BC', 'BD']
This is a nested iteration: for each a
in "AB"
, we iterate b
in "CD"
and concatenate a + b
.
In other words, this comprehension has two loops:
The first loop takes each letter
a
from"AB"
→ first"A"
, then"B"
.For each
a
, the second loop takes each letterb
from"CD"
→"C"
, then"D"
.The expression
a + b
joins the two letters into a pair.
So the program first makes "AC"
and "AD"
(with a = "A"
), and then "BC"
and "BD"
(with a = "B"
).
Exercise 6: Word lengths#
From the sentence "List comprehensions are powerful"
, use list comprehension to make a list of word lengths.
Hint
Have a look at the split()
method: https://www.w3schools.com/python/ref_string_split.asp.
Solution
sentence = "List comprehensions are powerful"
lengths = [len(word) for word in sentence.split()]
# lengths list: [4, 14, 3, 8]
split()
tokenizes the sentence by whitespace; we then apply len(...)
to each word and collect the lengths.
Exercise 7: Loop to comprehension#
Rewrite this loop as a list comprehension:
result = []
for x in range(20):
if x % 5 == 0:
result.append(x // 5)
Solution
result = [x // 5 for x in range(20) if x % 5 == 0]
# result list: [0, 1, 2, 3]
Execution order is loop → condition → expression: iterate x
in 0..19
, keep multiples of 5, then transform with x // 5
.
Key Points#
List comprehensions are a quick way to build lists.
General syntax:
[expression for item in iterable if condition]
.They work like loops: go through items, check condition, add result.
Good for simple transform or filter but use loops if it gets too complex.