No history yet

Iterables and Comprehensions

A More Pythonic Way to Loop

You're already familiar with using for loops to build new lists. It's a fundamental pattern: create an empty list, loop over an existing collection, and append a new value on each iteration. It works, but it's verbose.

squares = []
for i in range(10):
    squares.append(i * i)

# squares is now [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Python offers a more direct and readable way to achieve the same result: a list comprehension. It's a compact syntax for creating a list based on an existing iterable. Think of it as a for loop collapsed into a single, elegant line.

squares = [i * i for i in range(10)]

# squares is also [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

The structure reads almost like a sentence: "make a new list with i * i for each i in the range of 10." This style is often described as more , a term for code that fits well with the language's design philosophy of clarity and simplicity.

Filtering with Conditionals

Comprehensions become even more powerful when you add conditional logic. Suppose you only want the squares of even numbers. With a standard for loop, you'd add an if statement inside.

even_squares = []
for i in range(10):
    if i % 2 == 0:
        even_squares.append(i * i)

# even_squares is [0, 4, 16, 36, 64]

A list comprehension handles this just as cleanly. You can place an if clause at the end, which acts as a filter. Only items from the iterable that satisfy the condition will be processed.

even_squares = [i * i for i in range(10) if i % 2 == 0]

# Same result: [0, 4, 16, 36, 64]

The pattern is: [expression for item in iterable if condition].

Beyond Lists

This powerful syntax isn't limited to lists. You can use a similar structure to create dictionaries and sets on the fly.

Dictionary Comprehension

noun

A concise way to create dictionaries. You specify both the key and the value within the expression.

To create a dictionary mapping each number from 0 to 4 to its square, you can write:

square_map = {x: x*x for x in range(5)}

# square_map is {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Likewise, set comprehensions use curly braces to create sets, automatically handling uniqueness for you. For example, to get the set of unique first letters from a list of words:

words = ["apple", "banana", "apricot", "blueberry", "cherry"]
first_letters = {word[0] for word in words}

# first_letters is {'a', 'b', 'c'}

Lazy vs Eager Evaluation

List, set, and dictionary comprehensions are powerful, but they share one characteristic: they are eager. They build the entire data structure in memory at once. This is fine for small collections, but what if you're processing a file with millions of lines or a stream of sensor data? Storing it all in a list could exhaust your computer's memory.

This is where generator expressions come in. They look almost identical to list comprehensions, but they use parentheses instead of square brackets.

# List comprehension (eager)
squares_list = [i * i for i in range(1000000)] # Builds a huge list now

# Generator expression (lazy)
squares_gen = (i * i for i in range(1000000)) # Creates an object, no list yet

The generator expression doesn't create a million-item list. Instead, it creates a special generator object. This object knows how to produce the values on demand, but it only calculates one value at a time, each time you ask for the next one in a loop. This approach is called lazy evaluation, and it's incredibly memory-efficient for large datasets.

Use a list comprehension [] when you need the full list in memory. Use a generator expression () when you want to iterate over a potentially large sequence without storing it all.

Now you can write more efficient and expressive Python. Let's review these new concepts.

Time to check your understanding.

Quiz Questions 1/6

What is the primary advantage of using a list comprehension compared to a traditional for loop for creating a list?

Quiz Questions 2/6

Which code snippet correctly generates a list of the squares of odd numbers from 0 to 9?

By mastering comprehensions and knowing when to use generators, you've taken a significant step toward writing clean, efficient, and truly Pythonic code.