Python list comprehensions explained for beginners
Turn a for loop that builds a new list into one line. You will curve scores, keep the ones that pass, and fix the syntax error beginners hit.

Why does building a new list in Python take an empty list, a loop, and an append, when all you wanted was the new values?
Short answer: a list comprehension builds that new list in one line, from the loop you already know. It doesn't change the original list.
By the end of this post you will curve a list of quiz scores, keep only the ones that pass, and give every score a label. You will also know the syntax error that shows up when those two ifs get swapped, and when a normal loop is the clearer line. New to loops? Start with Introduction To Loops (opens in a new tab), then come back.
The awkward part is the empty list
Say you have quiz scores, and you want each score plus a 5-point curve. A loop can visit every score, which is the idea in Introduction To Loops (opens in a new tab). The awkward part is that the loop by itself only visits. If you want a new list, you have to build it yourself, which is why the important line is easy to bury.
scores = [12, 7, 19, 3, 15]
curved = []
for score in scores:
curved.append(score + 5) # the value you actually wanted
print(curved) # [17, 12, 24, 8, 20]
print(scores) # [12, 7, 19, 3, 15]score + 5 is the whole job, and it sits inside append, after a list you had to create first. Miss that empty curved = [] and Python has nowhere to put the new values. The original scores list is still [12, 7, 19, 3, 15], which is what you want when the curve is a new view of the quiz rather than a rewrite of the raw scores.
This is the pattern a list comprehension compresses. The same five scores stay with us for the rest of the post, so each version can be checked against the same numbers.
The same steps, written as the result
scores = [12, 7, 19, 3, 15]
curved = [score + 5 for score in scores] # value first, then the loop
print(curved) # [17, 12, 24, 8, 20]The part before for is the value that goes into the new list. The part after for is where each score comes from, which is the same loop as before, written beside the result instead of above an append. The square brackets are what make the result a list. Take the first score, 12. Python binds score to 12, evaluates score + 5, and puts 17 into the new list. Then it does the same for 7, and so on, until 15 becomes 20. That is the whole mechanism. There is no hidden second pass.
Python builds curved immediately, from left to right, so the list exists as soon as the line finishes. It isn't a recipe that waits until you ask for the next item. For five quiz scores, that difference doesn't matter. It matters later, when the source is huge and you didn't mean to hold every result in memory at once.
Once you have seen it on the scores, the shape is [expression for item in items]. The expression is the value you want. The item is your name for one element. The items are the list you already have.
Keep only the scores that pass
A curve changes every score. A filter keeps some of them and drops the rest. The condition goes at the end, because it decides whether the item is included, not what the item becomes.
scores = [12, 7, 19, 3, 15]
passing = [score for score in scores if score >= 10] # keep, don't relabel
print(passing) # [12, 19, 15]Walk the same list once. 12 stays, 7 is left out, 19 stays, 3 is left out, and 15 stays. There is no else here, and that is correct, because a score under 10 doesn't need a replacement value. It isn't in the new list. The Filtering With If (opens in a new tab) lesson stays on that if at the end of the line.
You can curve and filter together when both jobs are still a single expression. [score + 5 for score in scores if score >= 10] keeps the passing scores and then adds 5, which is why the result is [17, 24, 20] rather than a label or the raw list.
Give every score a label
Sometimes you want every item, and the value depends on a test. That if belongs with the expression, and it needs an else, because a value slot can't be empty.
scores = [12, 7, 19, 3, 15]
labels = ["pass" if score >= 10 else "retry" for score in scores]
print(labels) # ['pass', 'retry', 'pass', 'retry', 'pass']"pass" if score >= 10 else "retry" is an ordinary conditional expression, the same choice you would write on a normal line of Python. The for still walks the list after that choice is written. Nothing is left out, which is why the new list is the same length as scores. The Conditional Expressions (opens in a new tab) lesson is that choice without the list around it.
These two ifs are the pair that confuses people, and the mix-up is about the job, not about memorising a position. An if at the end filters, so some items are left out and there is no else. An if / else in the expression labels every item, so the new list stays the same length. If you can say which of those jobs you wanted, the position follows.
Common mistakes
This looks almost right, and Python rejects it:
scores = [12, 7, 19, 3, 15]
# SyntaxError: expected 'else' after 'if' expression
labels = ["pass" if score >= 10 for score in scores]- Putting
ifin the expression withoutelse. Python reads thatifas a conditional expression, which needs both results. If you meant to keep the passing scores, move the test to the end and drop the label. If you meant to label every score, give the expression anelse. - Expecting
scoresto change. A comprehension builds a second list. Ifscoresstill looks the same after the line runs, that is the feature, not a missed assignment. Assign the result, as incurved = [...], or you will build a list and immediately throw it away. - Using a comprehension to print or save as you go. The job of the line is a new list. If each item needs a
print, aninput, or several steps, a normalforloop is the line you can still read next week. - Nesting a second loop in the same line. Python allows
[a for row in rows for a in row]when you want one flat list. It is the wrong tool while you are still learning the first loop, because the line stops explaining itself.
When a loop is the clearer line
Use a comprehension when the job is a new list, one expression, and maybe one filter. Use a loop when the body needs several steps, when you are printing or saving as you go, or when a second loop would make the line something you have to decode. The comprehension isn't a replacement for every loop. It is the short form of the empty-list pattern.
A dict comprehension is the cousin people reach for by accident. It uses curly braces and a key, as in {score: score + 5 for score in scores}, and the result is a dictionary, not a list. The Dict Comprehensions (opens in a new tab) lesson covers that shape. If you are still choosing between a list and a dictionary, lists, tuples and dictionaries is the shorter decision guide.
| List comprehension | for loop | Dict comprehension | |
|---|---|---|---|
| What you get | A new list | Whatever the body does | A new dictionary |
| When it fits | One expression, maybe one filter | Several steps, printing, or saving | A key for each item |
| What happens to the original | It stays as it was | It changes only if you edit it | It stays as it was |
Quick recap
- A list comprehension builds a new list. It doesn't edit
scoresin place. - The value you want comes before
for. The source list comes after it. ifat the end filters. Some items are left out, and there is noelse.if/elsebeforeforlabels every item, so the new list stays the same length.- Use a normal loop when the body is more than one expression.
Frequently asked questions
What is a list comprehension in Python?
It is a single line that builds a new list from an existing sequence. You write the value you want, then the for that supplies each item, inside square brackets.
Is a list comprehension better than a for loop?
It is often the clearer line when the job is a new list and one expression. It isn't better when the body has several steps. For a short list of scores, speed isn't the reason to pick one.
Can a list comprehension filter items?
Yes. Add if at the end, as in [score for score in scores if score >= 10]. That test decides membership, and it doesn't change the score.
Does a list comprehension change the original list?
It doesn't. It builds a second list. If you want the curve to replace the name scores, assign it back, and know that you are choosing to drop the raw scores from that name.
What is the difference between a list comprehension and a generator?
Parentheses, as in (score + 5 for score in scores), make a generator, which produces one value at a time when you ask. Square brackets build the whole list now. For these quiz scores, the list is the one you want, because you are about to print it and use it.
Practice
The matching exercise is the List Comprehensions (opens in a new tab) lesson, which asks you to build the curved list yourself. It runs in the browser, so there is nothing to install. If the filter or the label still feels slippery, the filtering and conditional lessons linked above are the next two clicks.
Where to go next
Open that lesson if you want to write the line yourself. If loops still feel rusty, start with Python for Beginners (opens in a new tab) and come back. Brad Traversy (opens in a new tab) teaches Intermediate Python (opens in a new tab), which is where this pattern sits beside filters, dictionaries, and the programs that use them.








