Velocity Reviews > Bug in list comprehensions?

# Bug in list comprehensions?

Iain King
Guest
Posts: n/a

 06-07-2006
I was playing with list comprehensions, to try and work out how doubled
up versions work (like this one from another thread: [i for i in
range(9) for j in range(i)]). I think I've figured that out, but I
found something strange along the way:

>>> alpha = ["one", "two", "three"]
>>> beta = ["A", "B", "C"]
>>> [x for x in alpha for y in beta]

['one', 'one', 'one', 'two', 'two', 'two', 'three', 'three', 'three']
>>> [x for x in y for y in beta]

['C', 'C', 'C']
>>> beta = [alpha, alpha, alpha]
>>> beta

[['one', 'two', 'three'], ['one', 'two', 'three'], ['one', 'two',
'three']]
>>> [x for x in y for y in beta]

['C', 'C', 'C']
>>> [y for y in beta]

[['one', 'two', 'three'], ['one', 'two', 'three'], ['one', 'two',
'three']]
>>> [x for x in y for y in beta]

['one', 'one', 'one', 'two', 'two', 'two', 'three', 'three', 'three']

Shoudn't both lines '[x for x in y for y in beta]' produce the same
list?
I'm guessing I'm the one confused here... but I'm confused! What's
going on?

Iain

Fredrik Lundh
Guest
Posts: n/a

 06-07-2006
Iain King wrote:

> I'm guessing I'm the one confused here... but I'm confused! What's
> going on?

/.../ the elements of the new list 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 a list element each
time the innermost block is reached.

the clauses nest from left to right, not from right to left, so "[x for
x in y for y in beta]" is equivalent to

out = []
for x in y:
for y in beta:
out.append(x)

</F>

Duncan Booth
Guest
Posts: n/a

 06-07-2006
Iain King wrote:

>>>> [x for x in y for y in beta]

> ['C', 'C', 'C']
>>>> [y for y in beta]

> [['one', 'two', 'three'], ['one', 'two', 'three'], ['one', 'two',
> 'three']]
>>>> [x for x in y for y in beta]

> ['one', 'one', 'one', 'two', 'two', 'two', 'three', 'three', 'three']
>
> Shoudn't both lines '[x for x in y for y in beta]' produce the same
> list?

[x for x in y for y in beta] is a shorthand for:

tmp = []
for x in y:
for y in beta:
tmp.append(x)

So x iterates over whatever y is before the loop starts, and y iterates
over beta (but that doesn't affect what x is iterating over).

The important thing is to remember that the order of 'for' and 'if'
statements is the same as though you had written the for loop out in full.

Sion Arrowsmith
Guest
Posts: n/a

 06-07-2006
Fredrik Lundh <(E-Mail Removed)> wrote:
>Iain King wrote:
>> I'm guessing I'm the one confused here... but I'm confused! What's
>> going on?

>the clauses nest from left to right, not from right to left, so "[x for
>x in y for y in beta]" is equivalent to
>
> out = []
> for x in y:
> for y in beta:
> out.append(x)

And a list comprehension doesn't get a namespace to itself (cf.
generator comprehensions) so "leaks" its variables. Exactly as
above. So the y being iterated over in "for x in y" is the y
from the previous inner iteration ("for y in beta").

--
\S -- http://www.velocityreviews.com/forums/(E-Mail Removed) -- http://www.chaos.org.uk/~sion/
___ | "Frankly I have no feelings towards penguins one way or the other"
\X/ | -- Arthur C. Clarke
her nu becomež se bera eadward ofdun hlęddre heafdes bęce bump bump bump