Concepts / Generator Expressions

Generator Expressions

When it passes, the expression is applied and its result is added to the new list.

  • Programming

From Source Items to a New List

A list comprehension is a concise way to create a new list by transforming or filtering elements from an existing list. Instead of describing the process as several separate steps, you place the transformation, the source iterable, and an optional condition into one expression.

python
Output
squares is [1, 4, 9, 16]. Each source item is transformed, and each transformed result is placed into the new list.
numbers[1, 2, 3, 4]numberone source itemnumber * numbertransformationsquares[1, 4, 9, 16]takes each itemis transformedadds result
How does each item move from the source iterable through the optional condition and expression to become an element in the resulting list?

Reading the Comprehension Structure

Definition

The basic list comprehension syntax is [expression for item in iterable if condition]. The condition is optional.

[starts the listexpressionvalue added to resultforiteratesitemcurrent source itemintakes items fromiterablesource collectionif conditionoptional filter]ends the listoptional
Which part produces the output, which part supplies the items, and where does the optional condition fit?
PartPurposeExample
expressionDetermines the value added to the new listnumber * number
itemNames the current item from the sourcenumber
iterableProvides the source itemsnumbers
conditionOptionally decides whether an item continuesnumber % 2 == 0

The roles of the main list comprehension components.

Read the structure from left to right, but understand its operation as a process. The iterable supplies an item. If a condition is present, that item is checked. When it passes, the expression is applied and its result is added to the new list. Without a condition, every source item reaches the expression.

Filtering Before Transforming

Worked example

Keep Even Numbers and Double Them

Create a new list containing twice each even number in the source list [1, 2, 3, 4, 5].

  1. 1
    Choose the expression

    The desired output is twice the item, so the expression is number * 2.

  2. 2
    Choose the iterable

    The source list is [1, 2, 3, 4, 5].

  3. 3
    Add the condition

    Only even numbers should continue, so the condition is number % 2 == 0.

  4. 4
    Assemble the comprehension

    Place the expression first, then the for item in iterable part, followed by the optional if condition.

  5. 5
    Trace the items

    The items 1, 3, and 5 fail the condition. The items 2 and 4 pass, so the expression produces 4 and 8.

Result

[4, 8]

Code walkthrough
numbers = [1, 2, 3, 4, 5]
doubled_even = [number * 2 for number in numbers if number % 2 == 0]
  1. 1
    number is 1: the condition fails, so no result is added.
  2. 2
    number is 2: the condition passes, so 2 * 2 produces 4.
  3. 3
    number is 3: the condition fails, so no result is added.
  4. 4
    number is 4: the condition passes, so 4 * 2 produces 8.
  5. 5
    number is 5: the condition fails, so no result is added.
  • The expression number * 2 determines each value placed in the result.
  • The for number in numbers part visits each source item.
  • The if number % 2 == 0 condition allows only even items to reach the expression.
Output
doubled_even is [4, 8].
source itemconditionno resultnew-list itemexpressioncheckfailspassesadd value
What happens to an input item when it passes the condition, and what happens when it fails before the transformation is applied?

Nested Source Loops

Nested list comprehensions combine multiple sources. The outer loop runs first. For each item produced by that outer loop, the inner loop runs completely. This means the order of the loops matters when tracing which combinations are considered.

python
Output
coordinates is [(1, "a"), (1, "b"), (2, "a"), (2, "b")]. The inner loop completes for row 1 before the outer loop moves to row 2.

What do you think happens?

What order will the pairs appear in for [(row, column) for row in [1, 2] for column in ["a", "b"]]?

  • [(1, "a"), (1, "b"), (2, "a"), (2, "b")]

  • [(1, "a"), (2, "a"), (1, "b"), (2, "b")]

  • [(2, "b"), (2, "a"), (1, "b"), (1, "a")]

Reveal answer
Answer:

[(1, "a"), (1, "b"), (2, "a"), (2, "b")]

The outer loop selects row 1 first, and the inner loop runs completely for that row. Only after columns "a" and "b" have been processed does the outer loop select row 2.

Mistakes in Structure

  • Common mistake

    Putting the expression after the loop instead of before it

    What it looks like
    [for number in numbers number * 2]
    Why it fails

    The basic structure places the expression before for item in iterable.

    Do this instead
    [number * 2 for number in numbers]
  • Common mistake

    Leaving out the source iterable

    What it looks like
    [number * 2 for number]
    Why it fails

    The comprehension needs an iterable after in so it knows where items come from.

    Do this instead
    [number * 2 for number in numbers]
  • Common mistake

    Treating the condition as the output expression

    What it looks like
    [number % 2 == 0 for number in numbers]
    Why it fails

    The expression determines what is added to the new list, while an optional condition determines which items continue.

    Do this instead
    [number for number in numbers if number % 2 == 0]
  • Common mistake

    Applying the condition before naming the source item

    What it looks like
    [number * 2 if number % 2 == 0 for number in numbers]
    Why it fails

    The source item and iterable belong in the for item in iterable part. The optional if condition follows that part.

    Do this instead
    [number * 2 for number in numbers if number % 2 == 0]
Before
[number * 2 if number % 2 == 0 for number in numbers]

The optional condition is placed inside the expression area, so the comprehension does not follow the stated structure.

After
[number * 2 for number in numbers if number % 2 == 0]

The expression comes first, the source loop follows it, and the optional condition comes after the iterable.

Best practice

When debugging, expand the comprehension into its conceptual sequence: identify the source iterable, inspect one item, evaluate the condition if present, and then evaluate the expression. This mirrors the item flow described for list comprehensions and makes misplaced components easier to spot.

Practice the Item Flow

EASY

Write a list comprehension that takes the source list [3, 6, 9, 12], keeps only items greater than 6, and transforms each retained item by adding 1.

Hints
  • The expression should add 1 to the current item.
  • The iterable is the source list.
  • Place the condition after the iterable.
python
Output
result is [10, 13]. The values 3 and 6 fail the condition. The values 9 and 12 pass, then become 10 and 13 through the expression.

Key Takeaways

  1. 1
    A list comprehension creates a new list by transforming or filtering items from an existing list.
  2. 2
    Its basic structure is [expression for item in iterable if condition], with the condition optional.
  3. 3
    The source iterable supplies items, the condition optionally filters them, and the expression produces values for the new list.
  4. 4
    When multiple sources are nested, the outer loop runs first and the inner loop completes for each outer item.
  5. 5
    To debug a comprehension, trace one source item at a time and check the placement of the expression, iterable, and condition.

At a glance

  • List comprehensions provide concise syntax for creating a new list from source items.
  • The expression comes first, followed by the source loop and optional condition.
  • A condition filters items before the expression creates their result values.
  • Nested comprehensions process the outer loop first and complete the inner loop for each outer item.
  • Tracing each item through the structure is an effective way to write and debug comprehensions.

Related concepts

More concepts starting with G