Aguy
Aguy

Reputation: 8059

Why is the order of multiple `for` list comprehension the way it is?

I know the right way to have multiple for in a nested list comprehension is as follows (Python 3):

lista = [[[1,2],[3],[4,5,6]],[[7],[8,9]]]

flatlista = [i for k in lista for j in k for i in j]
# results with [1, 2, 3, 4, 5, 6, 7, 8, 9]

But my natural language instincts strongly object. I would have (wrongly) expected the code to be:

flatlista = [i for i in j for j in k for k in lista]

The wrong version sounds almost like English and is read in one stream left to right. The correct version requires some nested reading skills skipping left and right to encompass the meaning.

Why is this syntax as it is? Why was the language built this way?

Upvotes: 6

Views: 920

Answers (3)

Maxpaw
Maxpaw

Reputation: 1

Just found your post as i was wondering the same

Well yes - seems like it should be read like a flatten for loop

paragraph = ["hi stackoverflow devs!", "i know there is a comment", "that comment is not the same"]
letters = []

for sentence in paragraph:
    for word in sentence.split(" "): 
        if word != "comment":
            for letter in word:
                letters.append(letter)

letters = [letter for sentence in paragraph for word in sentence.split(" ") if word != "comment" for letter in word]

print(letters)

Upvotes: 0

JustinFisher
JustinFisher

Reputation: 693

Just remember the famous line from Casablanca: "Of all the gin joints in all the towns in all the world..." And then remember that the Python equivalent is backwards from that.

[ginjoint for town in world for ginjoint in town] 

Because who wants their programming language to sound like the greatest movie of all time?

Upvotes: 4

Martijn Pieters
Martijn Pieters

Reputation: 1121744

Because that's what PEP 202 -- List Comprehensions set it to. The PEP doesn't quite motivate why however, as it was created as an afterthought; the discussion had taken place on the development lists years before the PEP was created, or even the PEP process had been created.

First of all, the order mirrors the order you'd nest for loops and if statements in Python code:

for k in lista:
    for j in k:
        for i in j:

This makes it very natural if you are already used to that ordering.

Looking at the very first discussions about the feature there appears to be precedent in other languages for the ordering. And indeed, Haskell has the same ordering: each successive generator refines the results of the previous generator.

Certainly, at some point Tim Peters (the originator of the proposal) states that the order used today is obvious to him, see this post:

I've posted my proposed translation into today's Python a few times already, with the intent that it be taken literally, not suggestively. This nests "for" loops with the leftmost outermost, so nails everything about the ordering semantics at all levels. Why that's become a debating point at all levels is beyond me .

Upvotes: 12

Related Questions