List Comprehensions
Manually writing a for-loop to build a new list every time is repetitive. List comprehensions are Python's built-in shorthand for exactly that pattern.
A shorthand for "build a new list by looping over this one".
1. Learning Objective
By the end of this session you will be able to:
- Rewrite a transforming for-loop as a list comprehension
- Rewrite a filtering for-loop (with an if) as a list comprehension
- Combine transform and filter in a single comprehension
- Recognise when a comprehension improves readability and when a plain loop is clearer
- Explain that a comprehension always produces a brand-new list
2. Pre-Coding Quiz
Answer these before reading the concept explanation or writing any code. It is fine to get these wrong โ that is the point. You need 4/5 to proceed to the lab.
Given names = [c["name"] for c in countries], what does this produce?
[c["name"] for c in countries] is shorthand for looping over countries and collecting c["name"] from each item into a new list. countries itself is untouched.What does [c for c in countries if c["region"] == "Africa"] produce?
if clause at the end filters which items get included. Since the expression before for is just c (the whole dict), the result keeps entire country dicts, filtered down to African ones.Which for-loop is exactly equivalent to squares = [n * n for n in [1, 2, 3]]?
You want the names of only the African countries in one line. Which comprehension does that?
[expression for item in iterable if condition]. Option a transforms to c["name"] and filters with if c["region"] == "Africa" in the correct positions.True or false: after running names = [c["name"] for c in countries], the original countries list has been changed.
countries is exactly as it was before, regardless of what the comprehension does.3. The Concept โ List Comprehensions
Both approaches read every item and collect a transformed value โ the comprehension is the loop, compressed onto one line.
From for-loop to comprehension โ the transform case
Recall from Session 06: building a new list from an old one always follows the same shape โ start empty, loop, append the transformed value.
countries = [
{"name": "Kenya", "region": "Africa"},
{"name": "Ghana", "region": "Africa"},
{"name": "Peru", "region": "Americas"},
]
# The longhand for-loop version
names = []
for c in countries:
names.append(c["name"])
# The exact same result as a list comprehension
names = [c["name"] for c in countries]
print(names) # ['Kenya', 'Ghana', 'Peru']
Adding a filter with if
A trailing if clause keeps only the items matching a condition โ equivalent to a for-loop with an if-check before the append.
# Longhand
african = []
for c in countries:
if c["region"] == "Africa":
african.append(c)
# Comprehension
african = [c for c in countries if c["region"] == "Africa"]
print(african)
# [{'name': 'Kenya', ...}, {'name': 'Ghana', ...}]
Combining transform and filter
You can transform and filter in the same expression โ the transform goes first, the filter goes last.
african_names = [c["name"] for c in countries if c["region"] == "Africa"]
print(african_names) # ['Kenya', 'Ghana']
When NOT to use a comprehension
Comprehensions are for building a list. If your loop body does something else โ printing, multiple statements, side effects โ a plain for-loop is clearer. Forcing everything into a comprehension hurts readability instead of helping it.
# Fine as a comprehension โ building a list
names = [c["name"] for c in countries]
# NOT a good fit โ this is printing, not building a list.
# Keep this as a normal for-loop:
for c in countries:
print(f"{c['name']} is in {c['region']}")
4. Lab
What you will build
A file called filters.py operating on the country list from Session 06.
Step-by-step instructions
Create the file and re-declare the country list
# filters.py
countries = [
{"name": "Kenya", "region": "Africa", "population": 54000000},
{"name": "Ghana", "region": "Africa", "population": 31000000},
{"name": "Peru", "region": "Americas", "population": 33000000},
{"name": "Japan", "region": "Asia", "population": 125000000},
]
Write the longhand for-loop version of extracting names
Do this first, on purpose, before the comprehension โ you need to see the shape being compressed.
names_longhand = []
for c in countries:
names_longhand.append(c["name"])
print(names_longhand)
Rewrite it as a comprehension and confirm identical output
names = [c["name"] for c in countries]
print(names)
print(names == names_longhand) # True
Filter countries with population over 50 million
large = [c for c in countries if c["population"] > 50_000_000]
print([c["name"] for c in large])
Combine transform and filter in one comprehension
Get just the names of Asian countries in a single line.
asian_names = [c["name"] for c in countries if c["region"] == "Asia"]
print(asian_names)
Prove the original list is untouched
print("Original length still 4:", len(countries) == 4)
5. Expected Files Changed
| File | Action | Why |
|---|---|---|
filters.py |
Created | Demonstrates transform, filter, and combined comprehensions. |
docs/sessions/session-07/index.html |
Created | This session document. |
6. Commit Checkpoint
Once the lab is complete and you can explain every line, make this exact commit:
git add filters.py docs/sessions/session-07/index.html
git commit -m "session-07: transform and filter countries with list comprehensions"
7. Code Review Checklist
Go through your code line by line and check each item:
8. Post-Coding Quiz
Same 5 questions. Take it again now that you have written and run the code. You need 4/5 to mark this session complete.
Given names = [c["name"] for c in countries], what does this produce?
[c["name"] for c in countries] is shorthand for looping over countries and collecting c["name"] from each item into a new list. countries itself is untouched.What does [c for c in countries if c["region"] == "Africa"] produce?
if clause at the end filters which items get included. Since the expression before for is just c (the whole dict), the result keeps entire country dicts, filtered down to African ones.Which for-loop is exactly equivalent to squares = [n * n for n in [1, 2, 3]]?
You want the names of only the African countries in one line. Which comprehension does that?
[expression for item in iterable if condition]. Option a transforms to c["name"] and filters with if c["region"] == "Africa" in the correct positions.True or false: after running names = [c["name"] for c in countries], the original countries list has been changed.
countries is exactly as it was before, regardless of what the comprehension does.9. Reflection Questions
Think through these after the post-quiz. No right answer โ they are for discussion.
- Rewrite
[c["name"] for c in countries if c["region"] == "Africa"]back into a longhand for-loop from memory. Does it match what you wrote in the lab? - Can you think of a loop body from Session 06 that would NOT translate well into a comprehension? Why not?
- Why might a reviewer reject a deeply nested comprehension even though it "works"?
- How is a list comprehension similar to the object destructuring pattern used in other languages you might know?
10. What Breaks If This Knowledge Is Missing?
- Unreadable one-liners: Overusing comprehensions for anything with side effects (printing, mutating something else, multiple conditions) produces code that is technically correct but very hard to read. Knowing when NOT to use one is as important as knowing the syntax.
- Data-layer filtering (Layer 4): In Session 28 you will build a data-access layer that filters and searches a country list. That entire layer is built from the comprehension patterns in this session.
- Testing assertions (Layer 5): Tests frequently assert on filtered results, e.g. "the returned list contains only African countries." If you cannot read a comprehension, you cannot verify what the test is actually checking.
11. What We Learned
Python concept mastered: List comprehensions โ transform, filter, and combined forms, and when a plain loop is the better choice.
Unlocks: You can now express "give me a new list built from this one" in a single readable line โ the core operation of the whole project.
Next session: Session 08 โ Functions and Lambda. We will look at functions properly โ defining reusable logic instead of repeating it, including the compact lambda syntax.