Chapters
Python114 chapters

CollectionsChapter 30 of 114

List Comprehension

Build a list from another one in a single readable line.

The shape

A comprehension builds a new list by walking an existing sequence. This loop:

Python
squares = []
for n in range(5):
    squares.append(n ** 2)
print(squares)

Output

[0, 1, 4, 9, 16]

becomes one line:

Python
squares = [n ** 2 for n in range(5)]
print(squares)

Output

[0, 1, 4, 9, 16]

Read it left to right: what to collect, then where it comes from.

Filtering

An if on the end keeps only some items:

Python
numbers = [1, 2, 3, 4, 5, 6]
evens = [n for n in numbers if n % 2 == 0]
print(evens)

Output

[2, 4, 6]

This is the idiomatic way to remove items from a list — build the list you want rather than deleting from the one you have.

Transforming and filtering together

Python
words = ["  Ada ", "grace", "", "  Katherine"]
cleaned = [w.strip().title() for w in words if w.strip()]
print(cleaned)

Output

['Ada', 'Grace', 'Katherine']

if/else goes in front

A filtering if goes at the end. A choosing if/else is part of the expression, so it goes at the front:

Python
numbers = [1, 2, 3, 4]
labels = ["even" if n % 2 == 0 else "odd" for n in numbers]
print(labels)

Output

['odd', 'even', 'odd', 'even']

Nesting

Two for clauses read in the same order as the nested loops they replace:

Python
grid = [[1, 2], [3, 4]]
flat = [value for row in grid for value in row]
print(flat)

Output

[1, 2, 3, 4]

Building a grid puts the inner comprehension in the expression slot:

Python
table = [[row * col for col in range(1, 4)] for row in range(1, 4)]
print(table)

Output

[[1, 2, 3], [2, 4, 6], [3, 6, 9]]

Set and dict comprehensions

The same shape with different brackets:

Python
words = ["ada", "grace", "ada"]
print(sorted({w for w in words}))
print({w: len(w) for w in words})

Output

['ada', 'grace']
{'ada': 3, 'grace': 5}

Generator expressions

Round brackets give a generator, which produces values one at a time instead of building the whole list. For a big input that saves the memory:

Python
numbers = range(1, 1000001)
print(sum(n for n in numbers if n % 3 == 0))

Output

166666833333

If you only need to feed a result into sum(), any(), max() or a for, the generator is the better choice.

Know when to stop

A comprehension should stay readable at a glance. When it needs two filters, a nested condition and a comment, write the loop:

Python
rows = [("Ada", 36), ("Grace", 45)]
labels = []
for name, age in rows:
    if age > 40:
        labels.append(f"{name} is over forty")
print(labels)

Output

['Grace is over forty']

Test yourself

2 questions

Where does a filtering if go in a comprehension?

Show the answer

At the end, after the for — A filtering if goes last. An if/else that chooses a value goes at the front, because it is part of the expression.

What does (n for n in numbers) give, with round brackets?

Show the answer

A generator that produces values one at a time — It never builds the whole sequence, which is what makes it cheap for large inputs.

Next chapter

Sort Lists

sort in place or sorted into a new list, with a key and a direction.