Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 20

Mastering Comprehensions for Concise Collections

Recommended resources

Introduction

In our last lesson, we focused on controlling iteration order with sorted() and reversed(), reinforcing the Pythonic principle of using built-in, expressive tools instead of manual, error-prone logic. You learned to iterate over data non-destructively, keeping your code clean and your original collections intact.

This lesson introduces one of Python's most powerful and idiomatic features: comprehensions. This is a core concept for moving away from a Java-style mindset. Where you might be accustomed to initializing an empty collection and then populating it with a for loop, comprehensions allow you to build lists, sets, and dictionaries in a single, readable line of code.

We will cover how to write list, set, and dict comprehensions to declaratively create new collections, transforming your verbose collection-building loops into concise and efficient expressions.


The Foundation: List Comprehensions

The most common use case for comprehensions is building a list. Let's start with a direct "Java-ism vs. Pythonic" comparison.

The Verbose Loop (The "Bad" Way)

If you want a list of squares from an existing list of numbers, the traditional approach, common in many languages, is to initialize an empty list and append to it inside a loop.

nums = [1, 2, 3, 4, 5, 6]
squares = []
for n in nums:
    squares.append(n * n)

print(squares)



# Output: [1, 4, 9, 16, 25, 36]

This works, but it's boilerplate. You have to read three lines to understand a single intent: "create a new list of squares."

The List Comprehension (The "Good" Way)

A list comprehension expresses this same logic in a single, descriptive line.

Traditional Loop vs. List Comprehension in Python
A side-by-side comparison of a traditional for-loop and a list comprehension for generating a list of squares. The comprehension is visibly more concise.

The syntax is [expression for item in iterable]. It almost reads like plain English.

nums = [1, 2, 3, 4, 5, 6]
squares = [n * n for n in nums]

print(squares)



# Output: [1, 4, 9, 16, 25, 36]

This isn't just "syntactic sugar"; it's a fundamental idiom that signals you are building a new collection, not just looping for side effects. For a clear walkthrough of this transition from a loop to a comprehension, the following video is an excellent guide.

Python Tutorial: Comprehensions - How they work and why you should be using them

Corey Schafer's tutorial provides a crystal-clear, step-by-step introduction to list comprehensions, starting from the basic for-loop you're familiar with.

Watch from the beginning to 05:24. The first part (to 02:33) covers the most basic syntax. The second part (to 05:24) shows how to apply a transformation (like squaring a number) within the comprehension. Notice the comparison to map and lambda, and why comprehensions are often considered more readable.


Adding Logic to Comprehensions

Comprehensions become even more powerful when you add logic.

Filtering with if

You can filter items from the source iterable by adding an if clause at the end. The syntax becomes [expression for item in iterable if condition].

Let's refactor a loop that builds a list of even numbers.

Verbose Loop:

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = []
for n in nums:
    if n % 2 == 0:
        evens.append(n)
print(evens)



# Output: [2, 4, 6, 8, 10]

Comprehension:

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = [n for n in nums if n % 2 == 0]
print(evens)



# Output: [2, 4, 6, 8, 10]

This pattern is equivalent to a for loop with a nested if statement.

List comprehension syntax

This short text from a university course provides a formal breakdown of the list comprehension syntax, including the optional if condition, and shows its direct equivalence to a for-loop.

Read the sections 'Creating new lists', 'Filtering', and 'General Syntax'. Pay close attention to the code block that explicitly shows how [ <expression> for <variable_name> in <sequence> if <condition> ] translates to a standard loop.

Nested Loops

You can also include multiple for clauses to handle nested loops. This is useful for creating combinations or flattening nested lists. The for clauses are listed in the same order as you would write them in a nested loop structure.

Verbose Loop (creating pairs):

pairs = []
for letter in 'ab':
    for num in range(3):
        pairs.append((letter, num))
print(pairs)



# Output: [('a', 0), ('a', 1), ('a', 2), ('b', 0), ('b', 1), ('b', 2)]

Comprehension:

pairs = [(letter, num) for letter in 'ab' for num in range(3)]
print(pairs)



# Output: [('a', 0), ('a', 1), ('a', 2), ('b', 0), ('b', 1), ('b', 2)]

The video from Corey Schafer also covers both filtering and nested loops clearly.

Python Tutorial: Comprehensions - How they work and why you should be using them

Let's continue with the same video to see how if conditions and nested loops are added to comprehensions.

Watch from 05:24 to 10:32. The first segment (to 07:45) explains filtering with if. The second (to 10:32) demonstrates nested for clauses. Notice how the order of the for clauses in the comprehension mirrors the order of the nested loops.

Conditional Expressions (if/else)

What if you want to change the output value based on a condition, rather than filtering? For this, you use Python's conditional expression (ternary operator) value_if_true if condition else value_if_false at the beginning of the comprehension.

Verbose Loop:

nums = [1, 2, 3, 4, 5, 6]
results = []
for n in nums:
    if n % 2 == 0:
        results.append('even')
    else:
        results.append('odd')
print(results)



# Output: ['odd', 'even', 'odd', 'even', 'odd', 'even']

Comprehension:

nums = [1, 2, 3, 4, 5, 6]
results = ['even' if n % 2 == 0 else 'odd' for n in nums]
print(results)



# Output: ['odd', 'even', 'odd', 'even', 'odd', 'even']

This is a common point of confusion. Remember:

  • if at the end filters items.
  • if/else at the beginning transforms the output for every item.

10 Ways to Use List Comprehension in Python (Dictionary and Sets, too!)

The syntax for a conditional expression can be a bit tricky at first. This video does an excellent job of explaining the if/else ternary operator inside a comprehension and why its position is different from a simple filtering if.

Watch the clip from 09:03 to 12:38. The author clearly explains the syntax free if membership is None else membership and points out that this is a ternary operator that determines the output value, which is why it's on the left side of the for clause.


Generalizing to Sets and Dictionaries

The same powerful syntax can be used to create sets and dictionaries simply by changing the brackets.

Set Comprehensions: {...}

Set comprehensions use curly braces {}. They are perfect for when you need to create a set of unique items from an iterable.

Verbose Loop:

nums = [1, 2, 2, 3, 1, 4, 5, 4, 5]
unique_squares = set()
for n in nums:
    unique_squares.add(n * n)
print(unique_squares)



# Output: {1, 4, 9, 16, 25} (order may vary)

Set Comprehension:

nums = [1, 2, 2, 3, 1, 4, 5, 4, 5]
unique_squares = {n * n for n in nums}
print(unique_squares)



# Output: {1, 4, 9, 16, 25}

Dictionary Comprehensions: {key: value ...}

Dictionary comprehensions also use curly braces but require a key: value pair in the expression part.

Verbose Loop (creating a name-to-length mapping):

names = ['Alice', 'Bob', 'Charlie']
name_lengths = {}
for name in names:
    name_lengths[name] = len(name)
print(name_lengths)



# Output: {'Alice': 5, 'Bob': 3, 'Charlie': 7}

Dictionary Comprehension:

names = ['Alice', 'Bob', 'Charlie']
name_lengths = {name: len(name) for name in names}
print(name_lengths)



# Output: {'Alice': 5, 'Bob': 3, 'Charlie': 7}

The video we've been using also concludes with clear examples of set and dictionary comprehensions.

Python Tutorial: Comprehensions - How they work and why you should be using them

To round out your understanding, let's see how the comprehension syntax applies to sets and dictionaries.

Watch the final part of the video from 10:32 to 15:38. It covers dictionary comprehensions (from 10:32) and set comprehensions (from 13:54), showing how the same principles apply with just a change in syntax.


Exercise: Refactor to Comprehensions

You have been given a list of dictionaries, each representing a user. Your task is to refactor the provided verbose loops into single-line comprehensions.




# initial_code.py
users = [
    {'id': 101, 'name': 'Alice', 'country': 'USA', 'active': True},
    {'id': 102, 'name': 'Bob', 'country': 'CAN', 'active': False},
    {'id': 103, 'name': 'Charlie', 'country': 'USA', 'active': True},
    {'id': 104, 'name': 'Diana', 'country': 'UK', 'active': True},
    {'id': 105, 'name': 'Eve', 'country': 'CAN', 'active': False},
]




# --- YOUR TASKS ---




# 1. Create a list of names of all active users.
#    Refactor this loop into a list comprehension.
active_user_names_loop = []
for user in users:
    if user['active']:
        active_user_names_loop.append(user['name'])
print(f"Loop result: {active_user_names_loop}")




# Your list comprehension here
active_user_names_comp = ...
print(f"Comp result: {active_user_names_comp}")





# 2. Create a set of unique countries from the user data.
#    Refactor this loop into a set comprehension.
unique_countries_loop = set()
for user in users:
    unique_countries_loop.add(user['country'])
print(f"\nLoop result: {unique_countries_loop}")




# Your set comprehension here
unique_countries_comp = ...
print(f"Comp result: {unique_countries_comp}")





# 3. Create a dictionary mapping user IDs to their names.
#    Refactor this loop into a dictionary comprehension.
id_to_name_map_loop = {}
for user in users:
    id_to_name_map_loop[user['id']] = user['name']
print(f"\nLoop result: {id_to_name_map_loop}")




# Your dictionary comprehension here
id_to_name_map_comp = ...
print(f"Comp result: {id_to_name_map_comp}")
Click to see the solution



# solution_code.py
users = [
    {'id': 101, 'name': 'Alice', 'country': 'USA', 'active': True},
    {'id': 102, 'name': 'Bob', 'country': 'CAN', 'active': False},
    {'id': 103, 'name': 'Charlie', 'country': 'USA', 'active': True},
    {'id': 104, 'name': 'Diana', 'country': 'UK', 'active': True},
    {'id': 105, 'name': 'Eve', 'country': 'CAN', 'active': False},
]




# 1. Create a list of names of all active users.
active_user_names_comp = [user['name'] for user in users if user['active']]
print(f"Comp result: {active_user_names_comp}")



# Expected: ['Alice', 'Charlie', 'Diana']





# 2. Create a set of unique countries from the user data.
unique_countries_comp = {user['country'] for user in users}
print(f"\nComp result: {unique_countries_comp}")



# Expected: {'USA', 'CAN', 'UK'}





# 3. Create a dictionary mapping user IDs to their names.
id_to_name_map_comp = {user['id']: user['name'] for user in users}
print(f"\nComp result: {id_to_name_map_comp}")



# Expected: {101: 'Alice', 102: 'Bob', 103: 'Charlie', 104: 'Diana', 105: 'Eve'}


Conclusion

You've just learned one of the most expressive features in Python. Mastering comprehensions is a significant step toward thinking and writing Pythonically.

Key Takeaways:

  • Comprehensions build collections: They are a concise syntax for creating lists, sets, and dictionaries from existing iterables.
  • Syntax follows a pattern:
    • List: [expr for item in iterable if condition]
    • Set: {expr for item in iterable if condition}
    • Dict: {key_expr: val_expr for item in iterable if condition}
  • Readability is key: Comprehensions state the what (the collection you're building) more directly than a for loop, which describes the how (initialize, loop, append).
  • Distinguish filtering from transforming:
    • Use if at the end to filter items from the source.
    • Use ... if ... else ... at the beginning to transform the output value for every item.

In our previous lessons, we learned how to control and manage iteration. Now you know how to build collections efficiently during iteration. In the next lesson, we will complete this picture by learning how to reduce an iterable to a single value using built-in functions like sum(), any(), and all().