Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

Why does a comprehension inside a comprehension create nested lists?

Quick answer

A comprehension inside another comprehension creates nested lists when the outer expression is itself a list. Each time the outer loop runs, it evaluates the inner comprehension and gets a list, then collects those lists into an outer list. The loop clauses run in the same order as equivalent nested loops, so their order also determines how values are grouped and arranged. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

Why does this give me a list of lists instead of one list? [[cell for cell in row] for row in grid]

Geez

Because the outer comprehension collects the result of its expression once for every row, and that expression is another comprehension: [cell for cell in row]. Each inner comprehension makes a list of that row’s cells. The outer comprehension then puts each of those row-lists into a new list. In other words, the outer list has one item per row, and each item is a list. This matches two nested loops: make a row-list for each row, then append that row-list to the result. [S1]

For example, assuming grid = [[1, 2], [3, 4]]:

nested = [[cell for cell in row] for row in grid]
# [[1, 2], [3, 4]]

The inner list is the key: if the expression before the outer for produces a list, the outer result will contain those lists.

Follow-up question

How can I tell which for is the outer loop? The one-line version is hard to read.

Geez

Read the comprehension from left to right, matching each for to a loop. In [[cell for cell in row] for row in grid], the inner comprehension is evaluated for each row selected by the outer clause. Its result is collected before the outer loop moves to the next row. Python’s tutorial describes comprehension clauses as following the same order as equivalent nested loops. [S1]

Written out, the logic is:

result = []
for row in grid:
    row_result = []
    for cell in row:
        row_result.append(cell)
    result.append(row_result)

The explicit loops make the grouping visible: row_result is a list, and each one gets appended to result. Use this expanded version when a comprehension is confusing or when you need to add steps; it is the same basic grouping, just easier to inspect.

Follow-up question

What if I want one flat list of all the cells, not one list per row?

Geez

Put both loops in the same comprehension and make the expression produce a single cell, not a row-list:

flat = [cell for row in grid for cell in row]
# [1, 2, 3, 4]

Here, row is chosen first, then cell runs through that row; each cell is added directly to flat. The Python tutorial gives this same loop ordering for flattening rows into one list. [S1] This traverses the first row from left to right, then the next row, preserving that row-by-row sequence. It doesn’t preserve row boundaries, so use the nested result if you’ll need to know later which row a value came from.

Follow-up question

Can changing the order of the loops change whether I get nested lists, or just change the values?

Geez

Both the expression and the loop arrangement matter. Nesting comes from the expression returning a list that the outer comprehension collects; changing the order of for clauses alone does not automatically flatten a list-producing expression. With a flat expression, changing clause order can change which combinations are visited first and therefore the result order. In the documented transpose example, a comprehension builds a list for each column index, so it produces a list of lists with the grid’s rows and columns reorganized. [S1]

A useful way to choose is to ask: “What should one item in my final list be?” If the answer is “a whole row,” use a list-producing inner expression. If it is “one cell,” use one cell as the expression and put the row and cell loops in the same comprehension. For a flat result, the comprehension visits cells row by row; it does not retain the row boundaries.

A practical checklist

  • Identify the expression before the outermost for and ask whether it returns a single value or a list.

  • Write out the equivalent loops if it is unclear when the inner list is created.

  • Choose the desired final item: a row-list for nested output, or an individual cell for flat output.

  • Read multiple for clauses from left to right to check the traversal order.

  • Try a tiny grid with known values and inspect whether row boundaries should be retained.

A few more useful answers

Does every comprehension inside another comprehension create nested lists?

Only when the outer comprehension’s expression produces a list. If that expression produces a single value, the outer result contains those values rather than lists.

Does flattening keep track of which row each value came from?

No. A flat list keeps the traversal order but not explicit row boundaries. Keep the nested structure if those boundaries matter.

What does the Python tutorial illustrate about these patterns?

It illustrates comprehension order, flattening rows, and a nested comprehension that transposes a matrix. These examples show common patterns; they do not establish that one output shape is best for every program. [S1]

Sources

References used for this guide.

  1. [S1] Python Tutorial: Data Structures — list comprehensions and nested list comprehensions
    docs.python.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work