Excusing the fact that the idiom is unclear in terms of its syntax and the behavior it should have, how does the 'for for' idiom for flattening a list of iterables work?
For example, this works:
>>> a = [[0, 1], [2, 3], [4, 5]]
>>> f = [x for l in a for x in l]
>>> f
[0,1,2,3,4,5]
...but so does this (the variables are all the same!):
>>> a = [[0, 1], [2, 3], [4, 5]]
>>> f = [a for a in a for a in a]
>>> f
[0,1,2,3,4,5]
And it's generalizable; we can go n-deep by expanding the comprehension further. For example, here n = 3:
>>> a = [[[0, 1], [2, 3]], [[4, 5]]]
>>> f = [a for a in a for a in a for a in a] # We just add in another 'for a in a' and...presto!
>>> f
[0,1,2,3,4,5]
So, this is weird – the variable a is ostensibly occurring with multiple values in the same expression without any explicit indication of which scope it is in (i.e. there are multiple scopes implied, one for each dimension of the list) and the value of a is different within each. Note that the comprehension is equivalent to the following for loop:
>>> l = []
>>> for x in x:
... for x in x:
...... for x in x:
......... l.append(x)
>>> l
[0,1,2,3,4,5]
...More Explicitly:
>>> l = []
>>> for b in a:
... for c in b:
...... for d in c:
......... l.append(d)
>>> l
[0,1,2,3,4,5]
We can try and map out the logic into the comprehension. Here are two examples:
# Example 1
>>> [d for c in a for b in c for d in b]
[0,1,2,3,4,5]
# Example 2
>>> [d for b in a for c in b for d in c]
[0,1,2,3,4,5]
Now just because the variable mappings of the examples above work, that doesn't mean either mapping makes any sense. I inferred both of these, but I can't for the life of me tell you what the logic behind the each example is. I was hoping by uncovering a mapping it would be clear, but I don't think either of these are. And herein lies my question:
What is the logical mapping for the nested comprehensions above and how does it generalize to n-dimensional lists of iterables?
And, to demonstrate:
What is the intuitive mapping for an n = 4 instance?
Update
The second mapping example (above) is the correct one. It seems blindingly obvious now. One way to see this, suggested in the answer to the duplicate question (see comments), is as follows:
>>> forest = [[[0, 1], [2, 3]], [[4, 5]]]
>>> [leaf for tree in forest for branch in tree for leaf in branch]
[0, 1, 2, 3, 4, 5]
And the generalization to n = 4 would be:
>>> forests = [[[[0, 1]], [[2, 3]]], [[[4, 5]]], [[[6, 7]]]]
>>> [leaf for grove in forest for tree in grove for branch in tree for leaf in branch]
[0, 1, 2, 3, 4, 5, 6, 7]
Mental model expanded.