Skip to content
Lesson 2 of 12

Step 1 of 8 · Reading · ~4 min

Learn

Lists and Tuples

List Comprehensions

You will be able to write the build-a-list loop as one expression, choose between dropping and replacing items, and build grids whose rows are independent lists.

In List Basics you created an empty list and called append inside a loop. A list comprehension is that same loop written inside square brackets, with the value to store written first.

The loop on one line

python

The shape is [expression for name in iterable], where an iterable is anything you can loop over: a list, a string or a range. For each item, Python evaluates the expression at the front and stores the result.

python

Filter or substitute: where the if sits

An if after the for is a filter: items that fail it are dropped, so the result can be shorter. An if ... else before the for is a conditional expression (a if cond else b): it picks one of two values for every item, so the result keeps the same length.

python

A conditional expression needs its else; a filter cannot have one: [p for p in prices if p > 0 else 0.0] raises SyntaxError: invalid syntax.

Several for clauses

Each extra for is one more nested loop, and the clauses read in the same order as the nested statements, outer first:

python

Flattening a grid is [v for row in grid for v in row]: [[1, 2], [3, 4]] becomes [1, 2, 3, 4].

Grids: one comprehension inside another

If the front expression is itself a comprehension, each outer pass produces a whole row. The outer for decides how many rows the result has; the inner for fills one row. To total the columns of grid = [[1, 2, 3], [4, 5, 6]], the result has one entry per column, so the column index is the outer loop and the rows are walked inside it:

python

Build fresh rows this way, with [[0] * 3 for _ in range(2)], never with [[0] * 3] * 2: that is the shared-row trap from List Basics. The name _ is an ordinary variable that signals "the loop variable is not used".

The same outer-columns, inner-rows pattern builds a transposed result, where each output row is one input column. Labelling each cell with its own coordinates shows which index goes where: for a 2 by 3 table, 3 rows of 2 labels.

python

Testing a whole list

all(list) is True if every item is true; any(list) if at least one is. A comprehension with a comparison in front makes the list of booleans they need: [n > 5 for n in nums] is one True or False per item. With the flattening form, [v > 0 for row in grid for v in row] is one flat list of booleans covering every cell of a grid.

python

Use a plain loop instead when the body prints, has several elif branches, or needs a third level of nesting.

Common mistakes

  • Filter and substitute swapped. [v for v in xs if v >= 0] on [3, -2, 5] gives [3, 5]: the item is dropped instead of replaced, so the output lines come out short. When every item must produce a value, the if ... else goes in front.
  • Rows that share one list. A grid made with [[0] * C] * R and then filled by index leaves every row equal to the last one written. Build it with [[0] * C for _ in range(R)] or an inner comprehension per row.
  • Inner and outer loops swapped. On a 2 by 3 grid, the wrong index outside gives 2 rows of 3 values where 3 rows of 2 were wanted. Indexing with a row number that is too big for the other direction raises IndexError: list index out of range.
  • Treating zero as positive. all([v >= 0 ...]) says yes for a grid containing 0, but zero is not greater than zero.

Your exercise

Print a grid transposed with a rule applied to each value, then one summary line. The starter prints each row with print(*row), which separates the items by single spaces, but prints the grid unchanged; replace the two TODO values using comprehensions. The most likely mistake is putting the wrong loop outside, giving the wrong shape or an IndexError.

Up nextTuples and UnpackingLists and Tuples

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…