Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Why does 2D list comprehension require the outer loop before the inner loop?

table = [[1, 11, 111], [2, 22, 222], [3, 33, 333]]
[cell for cell in row for row in table] # Error
[cell for row in table for cell in row] # [1, 11, 111, 2, 22, 222, 3, 33, 333]

Intuitively, the first list comprehension makes more sense. It's moving from specific to less specific, i.e. cell -> row -> table. (I find this really weird about Python list comprehensions, it should be table -> row -> cell, but I digress.)

What's the logic behind cell -> table -> row? How does the parser see this?

like image 408
Leo Jiang Avatar asked Sep 11 '25 16:09

Leo Jiang


1 Answers

The for loops are meant to be the same as if you wrote them out the "normal" way:

for row in table:
    for cell in row:
        print(cell)

So when you pull this into a list comprehension, you leave the loops as is (except for removing the ":") and just pull the final expression to the start:

# you can actually "abuse" list comprehensions to have short
# loops like this, even if you don't care about the list being
# generated. It's generally not a great practice though
[print(cell) for row in table for cell in row]

I admit it is a bit confusing when you just read the code left to right. You just have to remember to read the loops first, then the beginning statement goes at the end. I suppose it could have been implemented as

[for row in table for cell in row cell]

but I think that looks even more confusing; it's harder to tell where the second loop ends and the statement within it starts. In the end, it's a design decision, though I'm sure some people would find the one approach or the other more intuitive.

like image 113
Nathan Avatar answered Sep 13 '25 06:09

Nathan