[Solved] Python List comprehension execution order [duplicate]


Order of elements

The PEP 202 is not very… comprehensive, but you can found some information in the Python Language Reference:

The comprehension consists of a single expression followed by at least one for clause and zero or more for or if clauses. In this case, the elements of the new container are those that would be produced by considering each of the for or if clauses a block, nesting from left to right, and evaluating the expression to produce an element each time the innermost block is reached.
[…]
The iterable expression in the leftmost for clause is evaluated directly in the enclosing scope and then passed as an argument to the implictly nested scope.

Therefore list comprehension proceeds for blocks from left to right.

But in your case, you have two list comprehensions having each one block:

  • outer list comprehension: do something for each row in matrix;
  • inner list comprehension(do something with row): do something else for each x in row.

That’s why your list comprehension is better read from right to left.
It is easier to see with a function:

>>> def square_elements(row): return [x**2 for x in row] # inner
...
>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [square_elements(row) for row in matrix] # outer
[[1, 4, 9], [16, 25, 36], [49, 64, 81]]

Consider now a two blocks list comprehension:

>>> [x**2 for row in matrix for x in row]
[1, 4, 9, 16, 25, 36, 49, 64, 81]

You see the left to right order. In the first case, you have: do something for each row in matrix, and that something is: do something else for each x in row. In the second case it is: do something for each x of each row in matrix.

Execution order

That’s the question you asked, even if I’m not sure that’s the question you wanted to ask! In which order the operation are performed? The spec doesn’t seem to say anything on this question but the answer is: it doesn’t matter, as long as you avoid side effects in your list comprehensions. If you get a list out of a list comprehension (no exception raised), this list is guaranteed to complete, no matter how it was built.

But if you don’t follow the “no side-effect” rule, the order in which side effects are performed may change the final result.
You can use a trick to test it: the print function returns None, hence if not print(...) is always True:

>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> squared = [[x**2 for x in row if not print("value", x)] for row in matrix if not print("row", row)]
row [1, 2, 3]
value 1
value 2
value 3
row [4, 5, 6]
value 4
value 5
value 6
row [7, 8, 9]
value 7
value 8
value 9
>>> squared
[[1, 4, 9], [16, 25, 36], [49, 64, 81]]

The order seems “natural”, but I don’t think you should rely on it (more important: you should not have side effects in your list comprehensions).

solved Python List comprehension execution order [duplicate]