Sythra

Article

Python list comprehensions: when to use them (and not)

List comprehensions turn a four-line loop into one readable line, until they don't. Learn the pattern, the filter form, and the point where a plain loop wins.

vaibhavkothari· Nov 12, 2026· 5 min readBeginner
ShareXLinkedIn
Python list comprehensions: when to use them (and not) cover

Sooner or later you read someone's Python and meet a line like this:

squares = [n * n for n in range(10)]

That is a list comprehensionA one-line way to build a new list by transforming or filtering another sequence. It does exactly what a short for loop does, in a more compact shape. This guide shows how to read one, how to write one, and — just as important — when to leave them alone.

The loop you already know

Start with a loop that builds a list:

squares = []
for n in range(10):
    squares.append(n * n)

print(squares)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Three things happen: make an empty list, loop, append each result. A comprehension collapses all three.

The pattern

[expression for item in iterable]

Read it left to right as a sentence: "give me expression, for each item in iterable."

names = ["ada", "grace", "linus"]
upper = [name.upper() for name in names]
print(upper)  # ['ADA', 'GRACE', 'LINUS']

The part before for is what goes into the new list. The part after it is the loop. Nothing else is hidden.

Add a filter with if

Put an if at the end to keep only some items:

numbers = [3, 8, 1, 12, 7, 20]
big = [n for n in numbers if n > 5]
print(big)  # [8, 12, 7, 20]

The loop version is:

big = []
for n in numbers:
    if n > 5:
        big.append(n)

You can transform and filter together:

words = ["Python", "is", "a", "language"]
lengths = [len(w) for w in words if len(w) > 2]
print(lengths)  # [6, 8]

If/else goes in front, not at the end

This is the part that trips beginners. A filter if goes after the loop. An if/else that chooses between two values goes before it, because it is part of the expression:

scores = [45, 82, 67, 91]
labels = ["pass" if s >= 60 else "fail" for s in scores]
print(labels)  # ['fail', 'pass', 'pass', 'pass']

Memory trick: if there is an else, the whole a if cond else b is the expression, so it sits first.

Real examples worth knowing

Clean up text read from a file:

lines = ["  hello \n", "world\n", "  \n"]
clean = [line.strip() for line in lines if line.strip()]
print(clean)  # ['hello', 'world']

Pull one field out of a list of dictionaries:

users = [
    {"name": "Ada", "age": 36},
    {"name": "Grace", "age": 45},
]
names = [u["name"] for u in users]
print(names)  # ['Ada', 'Grace']

Flatten a nested list with two loops (read the for parts in the same order you would write nested loops):

grid = [[1, 2], [3, 4], [5, 6]]
flat = [x for row in grid for x in row]
print(flat)  # [1, 2, 3, 4, 5, 6]

Dictionary and set versions

The same idea works for dictionaries and sets using braces:

word_lengths = {w: len(w) for w in ["apple", "fig", "banana"]}
print(word_lengths)  # {'apple': 5, 'fig': 3, 'banana': 6}

unique_lengths = {len(w) for w in ["apple", "fig", "pear"]}
print(unique_lengths)  # {3, 4, 5}

When a comprehension is the wrong tool

Comprehensions are for building a collection. They get worse the moment you stretch them.

Too much logic. If you need a nested if inside a nested for with a function call, a loop is easier to read and debug:

# Hard to scan
result = [transform(x) for row in data for x in row if x is not None and x > 0 and valid(x)]

# Easier
result = []
for row in data:
    for x in row:
        if x is None or x <= 0 or not valid(x):
            continue
        result.append(transform(x))

Side effects. Do not use a comprehension just to run something. This builds a throwaway list of None values:

[print(n) for n in range(3)]   # works, but misleading
for n in range(3):             # say what you mean
    print(n)

Huge data you only loop over once. A comprehension builds the entire list in memory. If you only need to iterate, use a generator expressionLike a list comprehension in parentheses; produces items one at a time instead of storing them all:

total = sum(n * n for n in range(1_000_000))

No brackets, no million-item list.

A simple rule of thumb

  • One transformation, maybe one filter, fits on one line → comprehension
  • You need to explain it with a comment → loop
  • You are not building a list → loop

Readable beats clever. A teammate (or you in three months) should understand the line without pausing.

Common mistakes

  • Putting else at the end. [x for x in items if x else 0] is a syntax error. Move the conditional to the front.
  • Forgetting the loop variable leaks nowhere. In Python 3 the variable inside a comprehension does not exist afterwards, unlike a normal for loop.
  • Modifying the list you are looping over. Build a new list instead; that is what comprehensions are for.

FAQ

What is a list comprehension in Python?

A list comprehension is a compact syntax for creating a list from another sequence: [expression for item in iterable if condition]. It replaces a loop that creates an empty list and appends to it.

Are list comprehensions faster than for loops?

Usually a little faster, because the append work happens in optimised internals. The difference rarely matters; choose based on readability first.

Can I use if and else in a list comprehension?

Yes. Put the if/else before the for: ["yes" if n > 0 else "no" for n in numbers]. A plain filter if goes after the for.

What is the difference between a list comprehension and a generator expression?

A list comprehension builds the whole list in memory immediately. A generator expression uses parentheses and produces values one at a time, which saves memory when you only iterate once.

Next reading on Sythra Articles

Keep reading

Related articles

Newsletter

Get new articles

Free essays on learning, Python, and ML — no account required. We’ll only email when there’s something worth reading.