DEV Community

mfaysal dev
mfaysal dev

Posted on Originally published at mfaysal.com

Python List Comprehension Examples Explained

A Python list comprehension builds a new list in one line by writing [expression for item in iterable], with an optional if at the end to filter items. It replaces the "make an empty list, loop, append" pattern. Below are the list comprehension examples I actually use, from the basic form to filtering, if/else, nested loops and the mistakes that tripped me up.

When I started learning Python, comprehensions looked like a puzzle. Once I learned to read them out loud, they became one of my favourite parts of the language. Every example here was run with Python 3.13, and the output in the comments at the bottom of each block is the real output.

The basic syntax: from a for loop to one line

Here is the same list of squares built two ways:

# The classic loop way
squares = []
for n in range(1, 6):
    squares.append(n * n)
print(squares)

# The same thing as a list comprehension
squares = [n * n for n in range(1, 6)]
print(squares)

# Output:
# [1, 4, 9, 16, 25]
# [1, 4, 9, 16, 25]
Enter fullscreen mode Exit fullscreen mode

The comprehension has three parts inside square brackets:

  • The expression (n * n): what goes into the new list.
  • The for clause (for n in range(1, 6)): where the items come from.
  • An optional condition (if ...): which items to keep.

The trick that helped me is to read it in plain English: "give me n * n for every n in 1 to 5." The result is always a brand new list. The original iterable is not changed.

Filtering with if

Put an if after the for clause and only the items that pass the test make it into the new list. This is the comprehension I write most often, usually to clean data before using it.

marks = [72, 45, 88, 39, 91, 60, 33]

# Keep only the passing marks (40 or more)
passed = [m for m in marks if m >= 40]
print(passed)

# Clean up messy user input: strip spaces, drop empty strings
raw_tags = ["  python ", "", "html", "   ", " css"]
tags = [t.strip().lower() for t in raw_tags if t.strip()]
print(tags)

# Output:
# [72, 45, 88, 91, 60]
# ['python', 'html', 'css']
Enter fullscreen mode Exit fullscreen mode

The second example does two jobs at once. The condition if t.strip() drops strings that are empty or only spaces, because an empty string counts as false. The expression t.strip().lower() then tidies up the ones that are left.

Using if/else in a list comprehension

This is the part that confused me the most. There are two different places a condition can go, and they do different things:

marks = [72, 45, 88, 39, 91]

# if/else goes BEFORE the for, because it decides the value
results = ["pass" if m >= 40 else "fail" for m in marks]
print(results)

# A filter goes AFTER the for, because it decides whether to keep the item
high = [m for m in marks if m >= 80]
print(high)

# Output:
# ['pass', 'pass', 'pass', 'fail', 'pass']
# [88, 91]
Enter fullscreen mode Exit fullscreen mode
  • x if condition else y before the for is a conditional expression. It runs for every item and decides what value goes in. The new list is always the same length as the original.
  • if condition after the for is a filter. It decides whether an item goes in at all, so the new list can be shorter.

If you write [m for m in marks if m >= 40 else 0], Python raises a SyntaxError, because a filter can't have an else. Move the whole if/else to the front instead.

List comprehension examples with real data

Practice lists of numbers are fine, but most of the time I'm working with a list of dictionaries, such as rows from a CSV file or a JSON response from an API. Comprehensions are great for pulling out exactly the fields you need.

students = [
    {"name": "Rafi", "mark": 72},
    {"name": "Nusrat", "mark": 88},
    {"name": "Tanvir", "mark": 39},
]

names = [s["name"] for s in students]
print(names)

toppers = [s["name"] for s in students if s["mark"] >= 70]
print(toppers)

# Pair two lists together with zip()
subjects = ["Math", "Physics", "Chemistry"]
scores = [81, 67, 74]
report = [f"{sub}: {score}" for sub, score in zip(subjects, scores)]
print(report)

# Output:
# ['Rafi', 'Nusrat', 'Tanvir']
# ['Rafi', 'Nusrat']
# ['Math: 81', 'Physics: 67', 'Chemistry: 74']
Enter fullscreen mode Exit fullscreen mode

The zip() example shows that the for clause can unpack values, just like a normal loop. for sub, score in zip(subjects, scores) walks through both lists side by side. Mixing in an f-string in the expression is a common way to build labels or lines of a report.

Nested list comprehensions

You can use more than one for in a comprehension, and you can put a comprehension inside another one. These are powerful, but they are also where readability goes downhill fast.

grid = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

# Flatten: read the for clauses left to right, like nested loops
flat = [n for row in grid for n in row]
print(flat)

# Build a 3x4 table of zeros (a list of lists)
table = [[0 for col in range(4)] for row in range(3)]
print(table)

# Transpose rows into columns
columns = [[row[i] for row in grid] for i in range(3)]
print(columns)

# Output:
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
# [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Enter fullscreen mode Exit fullscreen mode

For the flatten example, read the for clauses in the same order you would write nested loops: first for row in grid, then for n in row. The table and columns examples are different: there the inner comprehension is the expression, so each item of the outer list is itself a new list.

My rule: if I need more than two for clauses, or a nested comprehension plus a condition, I write a normal loop. Code is read more often than it is written.

Dict comprehensions, set comprehensions and generator expressions

The same syntax works with other brackets. Curly braces with a key: value pair give you a dictionary, and curly braces with a single value give you a set. Round brackets give you a generator expression, which produces values one at a time instead of building a whole list in memory.

words = ["apple", "banana", "avocado", "cherry", "apple"]

# Dict comprehension: word -> length
lengths = {w: len(w) for w in words}
print(lengths)

# Set comprehension: unique first letters
first_letters = {w[0] for w in words}
print(sorted(first_letters))

# Generator expression: no list is built, sum() pulls values one by one
total_chars = sum(len(w) for w in words)
print(total_chars)

# Output:
# {'apple': 5, 'banana': 6, 'avocado': 7, 'cherry': 6}
# ['a', 'b', 'c']
# 29
Enter fullscreen mode Exit fullscreen mode

Notice that "apple" appears twice in the input but only once in the dictionary, because a later key overwrites an earlier one. I sorted the set before printing, since sets have no guaranteed order. When you only need to pass the values into a function like sum(), max(), any() or "".join(), a generator expression is enough, and you can drop the extra brackets.

Bonus: the walrus operator inside a comprehension

Sometimes the filter and the expression need the same calculated value. Since Python 3.8, the assignment expression := lets you compute it once and reuse it:

readings = ["12", "x", "7", "", "30"]

def to_int(text):
    try:
        return int(text)
    except ValueError:
        return None

# := stores the converted value so to_int() runs only once per item
numbers = [n for r in readings if (n := to_int(r)) is not None]
print(numbers)

# Output:
# [12, 7, 30]
Enter fullscreen mode Exit fullscreen mode

Without :=, you would call to_int() twice per item, once in the filter and once in the expression. It's a handy tool, but use it lightly, because it makes the line harder to read for beginners.

Common mistakes with list comprehensions

1. Putting else in the wrong place

As covered above, if alone goes at the end, while if ... else ... goes at the front. When you get a SyntaxError in a comprehension, check this first.

2. Using a comprehension only for its side effects

A comprehension is for building a list. If you only want to do something for each item, like printing or saving to a file, use a normal loop:

names = ["rafi", "nusrat"]

# Don't do this: a list of None values built only for the side effect
result = [print(n.title()) for n in names]
print(result)

# Do this instead
for n in names:
    print(n.title())

# Output:
# Rafi
# Nusrat
# [None, None]
# Rafi
# Nusrat
Enter fullscreen mode Exit fullscreen mode

The first version works, but it also builds a useless list of None values, because print() returns None. Anyone reading it will wonder what result is for.

3. Expecting the loop variable to exist afterwards

In Python 3, a comprehension has its own scope, so its loop variable does not overwrite a variable with the same name outside it:

x = "outer"
values = [x for x in range(3)]
print(values)
print(x)  # the loop variable does not leak out in Python 3

# Output:
# [0, 1, 2]
# outer
Enter fullscreen mode Exit fullscreen mode

This is a good thing, but it means you can't use the loop variable after the comprehension ends, the way you can after a normal for loop.

4. Cramming too much into one line

A comprehension that runs past the edge of the screen, with function calls, conditions and nested loops, is not clever. It's just hard to debug. Split long comprehensions over several lines inside the brackets, or switch to a loop.

5. Building a big list you don't need

sum([x * x for x in range(1_000_000)]) creates a million-item list first. sum(x * x for x in range(1_000_000)) gives the same answer without storing the list.

FAQ

Are list comprehensions faster than for loops?

For simple cases they are usually a bit faster than a loop that calls append(), because there is less work per item. The difference is rarely what matters, though. Choose a comprehension because it's clearer for building a list, not to save microseconds.

Can I use elif in a list comprehension?

There is no elif keyword inside a comprehension, but you can chain conditional expressions: ["A" if m >= 80 else "B" if m >= 60 else "C" for m in marks]. It works, but past two conditions I move the logic into a small function and call that function in the expression.

What's the difference between a list comprehension and map()?

map(func, items) applies a function to every item and returns a lazy iterator. A list comprehension does the same job and can filter at the same time, and many Python developers find it easier to read. Both are fine. I mostly use comprehensions.

Do list comprehensions work with strings and files?

Yes. Any iterable works: strings give you characters, range() gives you numbers, and an open file gives you lines, so [line.strip() for line in f] is a common way to read a file into a clean list.

Conclusion

A list comprehension is a short way to say "build a new list from this iterable, transform each item, and optionally skip some". Start with the basic form, add a filter at the end when you need one, and remember that if/else goes at the front. When a comprehension gets hard to read, a plain loop is always allowed.

The official Python tutorial has a good section on list comprehensions with more examples if you want to go deeper. I'm still learning too, and you can see what I've been building on my projects page.

Originally published at mfaysal.com.

Top comments (0)