Python List Comprehensions
Table of Contents + β
In the last lesson you learned List Slicing, which is how you grab a piece of a list. Now we go one step further. Instead of pulling parts out of a list, you often want to build a brand new list from one you already have. Maybe you have a list of prices and you want all of them with tax added. You could write a loop for that. But Python gives you a shorter, cleaner way. It is called a list comprehension.
π€ Why List Comprehensions?
Say you have some numbers and you want a new list where every number is doubled. The normal way is to make an empty list, loop over the numbers, and add each doubled value one by one.
Here is that loop doing exactly that:
nums = [1, 2, 3, 4]doubled = []for n in nums: doubled.append(n * 2)print(doubled)Output
[2, 4, 6, 8]That works fine. But see how much typing it takes just to say βdouble each numberβ? You need three extra lines for one simple idea. A list comprehension lets you say the same thing in a single line. That is the pain it solves. Less noise, same result.
π§© What Is a List Comprehension?
A list comprehension is a short way to build a new list from a sequence you already have. You write the rule for each item right inside the square brackets. Then Python builds the whole list comprehension for you.
Think of it like a small factory. Raw items go in on one side. Each one gets the same treatment. A finished list comes out the other side. You describe the treatment once, and the factory handles the rest.
The shape looks like this:
new_list = [expression for item in sequence]Let me break that down in plain words:
expressionis what you want each new item to be. This is the work, liken * 2.itemis the name for one thing as you go through the sequence. You pick this name.sequenceis the list (or range, or string) you are reading from.
Read it left to right and it almost sounds like English. βGive me n * 2 for each n in nums.β
πͺ The Same Job, Two Ways
Here is the doubling example again. This time the comprehension sits right next to the loop. Both produce the exact same list.
This is the loop version you already saw:
# The loop waynums = [1, 2, 3, 4]doubled = []for n in nums: doubled.append(n * 2)And this is the comprehension version:
# The comprehension waynums = [1, 2, 3, 4]doubled = [n * 2 for n in nums]print(doubled)Output
[2, 4, 6, 8]Look at the two side by side. The n * 2 is your expression. The for n in nums is the same loop header you already know. The comprehension just folds the empty list, the loop, and the append into one tidy line.
Tip
A good way to read any comprehension is back to front. First spot the for ... in ... part to see what you are looping over. Then look at the expression on the left to see what happens to each item.
Here is the same idea with text. Say Alex has a list of names and wants them all in uppercase for a header row.
names = ["alex", "riya", "arjun"]shouted = [name.upper() for name in names]print(shouted)Output
['ALEX', 'RIYA', 'ARJUN']The expression here is name.upper(). Same shape, different work.
π Adding a Condition
Often you do not want every item. You only want the ones that pass a test. Maybe just the positive numbers, or just the even ones. For that you add an if condition at the end of the comprehension.
The shape grows a little:
new_list = [expression for item in sequence if condition]The if condition works like a filter. An item is only included when the condition is true. Everything else is skipped.
Say you have a mix of positive and negative numbers and you only want to keep the positive ones.
nums = [4, -2, 7, -9, 3, -1]positives = [x for x in nums if x > 0]print(positives)Output
[4, 7, 3]Notice the expression here is just x. You are not changing the numbers. You are only deciding which ones to keep. The if x > 0 does the choosing. Each negative number fails the test, so it never gets into the new list.
Now let us combine both ideas. We will change the items and filter them at the same time. Here we keep only the even numbers and square each one.
nums = [1, 2, 3, 4, 5, 6]even_squares = [n * n for n in nums if n % 2 == 0]print(even_squares)Output
[4, 16, 36]Walk through it slowly. n % 2 == 0 keeps only the even numbers, so 2, 4, and 6 get through. Then n * n squares each of those. The odd numbers were dropped before the squaring ever happened.
Note
The if here filters which items get in. There is a different kind of if (a full if-else) that changes the value, but that goes in the expression part, not at the end. We are keeping to the simple filter for now.
π§ A Real Example
Imagine you run a small online store. You have a list of prices and you want a new list with a fifteen percent discount applied. But you only want it for items that cost more than 100. Cheaper items stay out of the sale.
Here is the whole thing in one line:
prices = [50, 120, 80, 200, 99, 150]sale_prices = [round(p * 0.85, 2) for p in prices if p > 100]print(sale_prices)Output
[102.0, 170.0, 127.5]Read it back to front. Loop over prices, keep only the ones where p > 100, then for each price that passed, compute p * 0.85 and round it to two decimals. The prices 120, 200, and 150 passed the test. The rest were under the limit, so they were left out. This builds a brand new list and never touches the original prices.
β οΈ Common Mistakes
A few things go wrong when people first use comprehensions.
- Cramming too much logic into one line. A comprehension should stay readable. If you find yourself nesting loops and conditions until it is a wall of text, stop and use a normal loop instead. Short and clear beats short and confusing.
# β Avoid: too much packed in, hard to read at a glanceresult = [x * y for x in range(10) for y in range(10) if x != y if x + y > 5]
# β
Good: a plain loop when the logic is heavyresult = []for x in range(10): for y in range(10): if x != y and x + y > 5: result.append(x * y)- Forgetting that the
ifgoes at the end (for filtering). When you are only keeping or dropping items, the condition belongs after theforpart.
# β Avoid: this is not how a filter is writtenevens = [n if n % 2 == 0 for n in nums] # SyntaxError
# β
Good: filter condition goes at the endevens = [n for n in nums if n % 2 == 0]- Expecting it to change the original list. A comprehension always builds a new list. The list you read from is not changed, so remember to store the result in a variable.
β Best Practices
- Reach for a comprehension when the goal is βbuild a new list from this one.β That is exactly what it is made for.
- Keep it to one transformation and at most one simple filter. The moment it gets hard to read out loud, switch to a regular loop.
- Pick a clear name for the item.
for price in pricesreads better thanfor p in x. - Give the new list a meaningful name too, so the next person knows what came out of the factory.
π§© What Youβve Learned
- β A list comprehension builds a new list from a sequence you already have, all in one clean line.
- β
The basic shape is
[expression for item in sequence], which does the same job as an empty list plus aforloop plusappend. - β
You can read any comprehension back to front. Find the
forpart first, then the expression. - β
Adding
if conditionat the end filters the items, so only the ones that pass the test get in. - β You can transform and filter at the same time, like squaring only the even numbers.
- β Keep comprehensions simple and readable. When the logic gets heavy, a normal loop is the better choice.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does [n * 2 for n in nums] do?
Why: The expression n * 2 runs for each n in nums, producing a brand new list of doubled values.
- 2
Where does the filter condition go in a list comprehension?
Why: For filtering, the if condition is written at the end: [x for x in nums if x > 0].
- 3
Given nums = [4, -2, 7, -9], what does [x for x in nums if x > 0] produce?
Why: The if x > 0 filter keeps only the positive numbers, and the expression x leaves them unchanged.
- 4
When is a regular for loop a better choice than a comprehension?
Why: If a comprehension turns into a confusing wall of nested loops and conditions, a plain loop is clearer.
π Whatβs Next?
You can now squeeze a whole loop into one clean line. Next we look at lists that hold other lists inside them, which opens up grids, tables, and more.