Quick Answer

A list comprehension is a short, one-line way to build a new list from any iterable in Python. The pattern is [expression for item in iterable if condition] — you write what each element should look like, loop over a source, and optionally filter it. It replaces the classic "create an empty list, loop, and append" pattern with cleaner, slightly faster code.

What is a Python list comprehension?

A Python list comprehension is a compact way to create a new list from an existing sequence — a range, another list, a string, a dictionary, anything you can loop over. Instead of writing a for loop that starts with an empty list and appends to it line by line, you describe the whole list in a single readable expression wrapped in square brackets.

Think of it as a sentence: "give me this value, for each item in that collection, but only if some condition is true." Once you get used to the shape, comprehensions make your code shorter and often easier to read for simple transformations. They are one of the most-used features in real Python code, so learning them early pays off.

New to Python entirely? This tutorial assumes you already know basic loops and lists. If not, our free Python course walks you through the fundamentals first, then comes back to features like this one.

The syntax, broken down

Every list comprehension follows the same skeleton:

[expression for item in iterable if condition]

Read it left to right and match each part to a plain-English idea:

  • expression — what each element of the new list should be (for example n * n).
  • for item in iterable — the loop that supplies values, exactly like a normal for loop.
  • if condition — an optional filter. Keep an item only when the condition is True. Leave this out and you keep everything.

The whole thing sits inside square brackets [ ], which is what tells Python you want a list back. That is the entire rule. Everything else in this tutorial is just this pattern used in different ways.

Basic example: a list of squares

Let's build a list of squares from 1 to 5. Here is the classic loop version first, so you can see what we are replacing:

squares = []
for n in range(1, 6):
    squares.append(n * n)

print(squares)  # [1, 4, 9, 16, 25]

Now the same result as a list comprehension:

squares = [n * n for n in range(1, 6)]

print(squares)  # [1, 4, 9, 16, 25]

Same output, one line instead of three. The expression is n * n, and range(1, 6) gives the numbers 1, 2, 3, 4, 5 (the end value 6 is not included). No filter here, so every number is squared and kept.

Filtering with an if condition

Add an if at the end to keep only the items you want. This example keeps just the even numbers from 1 to 10:

evens = [n for n in range(1, 11) if n % 2 == 0]

print(evens)  # [2, 4, 6, 8, 10]

The expression here is simply n — we are not transforming the values, only selecting them. The condition n % 2 == 0 is True when a number divides evenly by 2, so odd numbers are dropped. The % operator returns the remainder after division.

You can combine transforming and filtering at once. For example, square only the even numbers:

even_squares = [n * n for n in range(1, 11) if n % 2 == 0]

print(even_squares)  # [4, 16, 36, 64, 100]

Using if-else to choose a value

There is a second, easy-to-confuse way to use if. When you want to pick between two values (not filter items out), you use a conditional expression, and its position changes:

labels = ["even" if n % 2 == 0 else "odd" for n in range(1, 6)]

print(labels)  # ['odd', 'even', 'odd', 'even', 'odd']

Notice the difference — this is the single biggest gotcha for beginners:

  • Filtering: the if goes after the loop, with no else. It decides whether to keep an item.
  • Choosing a value: the if ... else ... goes before the for, as part of the expression. It always produces a value for every item.

A quick memory aid: "filter-if" comes last; "choose-if-else" comes first. If you ever get a SyntaxError around an if, check that you put it in the right spot.

Nested loops and flattening lists

A comprehension can hold more than one for. The loops read in the same order you would write them normally — the leftmost is the outer loop. Here we build every pair of coordinates:

pairs = [(x, y) for x in range(1, 3) for y in range(1, 3)]

print(pairs)  # [(1, 1), (1, 2), (2, 1), (2, 2)]

A very common real use is flattening a list of lists into a single list:

matrix = [[1, 2, 3], [4, 5, 6]]
flat = [num for row in matrix for num in row]

print(flat)  # [1, 2, 3, 4, 5, 6]

Read the loops as "for each row in the matrix, for each num in that row." That said, two loops is usually the limit before readability suffers. Three or more nested for clauses in one line is a strong sign you should switch back to a regular loop.

Dict and set comprehensions

The same idea works for dictionaries and sets — just swap the brackets. Use curly braces { } and, for a dictionary, a key: value pair as the expression:

squares_dict = {n: n * n for n in range(1, 5)}

print(squares_dict)  # {1: 1, 2: 4, 3: 9, 4: 16}

A set comprehension also uses curly braces but has no colon. It automatically removes duplicates, just like a normal set:

words = ["hi", "bye", "yes", "no"]
unique_lengths = {len(word) for word in words}

print(unique_lengths)  # {2, 3}

The four words have lengths 2, 3, 3, and 2, but the set keeps only the distinct values. So the rule is simple: square brackets give you a list, {key: value ...} gives you a dict, and {value ...} gives you a set.

For loop vs list comprehension: which to use

Comprehensions do not replace for loops — they are a tool for one specific job: building a new collection. A plain loop is still the right choice when your logic is bigger than a single expression. Here is a quick side-by-side:

What you care aboutPlain for loopList comprehension
Short, one-line codeNoYes
Best for simple transforms and filtersPartialYes
Best for complex, multi-step logicYesNo
Usually a bit fasterNoYes
Room for many statements and debuggingYesNo

Comprehensions are typically a little faster than an equivalent loop because Python optimises them internally, but for most beginner programs the speed difference is tiny. Choose based on readability first, not micro-performance.

When NOT to use a list comprehension

Comprehensions are great until they are not. Reach for a normal loop when any of these are true:

  • The line gets long or hard to read. If you have to squint to find the for, it is too much. Clear code beats clever code every time.
  • You need multiple steps or statements. Comprehensions can only hold expressions, not things like print() for logging, try/except, or intermediate variables.
  • You are only doing a side effect. Never write a comprehension just to call a function and throw the list away — use a plain for loop. It signals your intent honestly.
  • The data is very large. A list comprehension builds the whole list in memory at once. If you only need to iterate once over millions of items, a generator expression — same syntax but with round brackets (n * n for n in range(1000000)) — is far more memory-friendly.

Our recommendation: use a comprehension for simple "transform and/or filter one collection into another" tasks, and fall back to a regular loop the moment the logic grows. Practise the pattern on small examples first — the free Priodemy Python course has exercises where comprehensions come up naturally, which is the fastest way to make them stick.

Frequently Asked Questions

What is a list comprehension in Python?

It is a concise, one-line way to create a new list from an existing iterable using the pattern [expression for item in iterable if condition]. It replaces the longer approach of creating an empty list and appending to it inside a loop.

Is a list comprehension faster than a for loop?

Usually a little, because Python optimises comprehensions internally, so they avoid the overhead of repeated append() calls. For small programs the difference is negligible, so pick whichever reads more clearly.

Can I use if-else inside a list comprehension?

Yes, but the position matters. A filtering if goes at the end ([n for n in items if n > 0]), while an if ... else ... that chooses a value goes before the for (["pos" if n > 0 else "neg" for n in items]).

What is the difference between a list, dict, and set comprehension?

They share the same pattern but use different brackets. Square brackets [ ] make a list, {key: value ...} makes a dictionary, and {value ...} makes a set (which drops duplicates automatically).

When should I avoid list comprehensions?

Avoid them when the line becomes hard to read, when you need multiple statements or error handling, or when you are only performing a side effect. In those cases a plain for loop is clearer and better.

How do I flatten a list of lists with a comprehension?

Use two for clauses in order: [num for row in matrix for num in row]. Read it as "for each row in the matrix, for each num in that row."