List comp bug?

T

tasjaevan

I seem to have stumbled across a problem with list comprehensions (or
perhaps it's a misunderstanding on my part)

[f() for f in [lambda: t for t in ((1, 2), (3, 4))]]

is giving me

[(3, 4), (3, 4)]

The equivalent using a generator expression:

[f() for f in (lambda: t for t in ((1, 2), (3, 4)))]

is giving me

[(1, 2), (3, 4)]

as expected.

Is this a known bug? I'm using Python 2.4.3

Thanks

James
 
P

Paul Rubin

I seem to have stumbled across a problem with list comprehensions (or
perhaps it's a misunderstanding on my part)

[f() for f in [lambda: t for t in ((1, 2), (3, 4))]]

List comprehensions are syntactic sugar for "for" loops. The
thing to notice is that in "lambda: t", t is unbound. It's not
the same as the loop index inside the list comp. Try:

[f() for f in [lambda t=t: t for t in ((1, 2), (3, 4))]]
 
F

Fredrik Lundh

I seem to have stumbled across a problem with list comprehensions (or
perhaps it's a misunderstanding on my part)

[f() for f in [lambda: t for t in ((1, 2), (3, 4))]]

is giving me

[(3, 4), (3, 4)]

The equivalent using a generator expression:

[f() for f in (lambda: t for t in ((1, 2), (3, 4)))]

is giving me

[(1, 2), (3, 4)]

as expected.

Is this a known bug?

no, it's not a bug, it's a consequence of the order in which things are done,
and different visibility rules for the loop variables used in list comprehensions
and generator expressions.

both the inner loops generates lambda expressions that return the value of
the "t" variable.

for the list comprehension, "t" is an ordinary variable (part of the surrounding
scope), and since the comprehension is completed before the resulting list is
returned, all lambdas end up referring to the same "t", which is set to the last
value:
x = [lambda: t for t in ((1, 2), (3, 4))]
x
x[0]() (3, 4)
t = "hello"
x[0]()
'hello'

in contrast, the generator expression uses a local loop variable "t", and only fetches
one value from the target sequence for each iteration, so all lambdas will be bound
to different objects.

any special reason you need to write this kind of convoluted code, btw?

</F>
 
T

Terry Reedy

[f() for f in [lambda: t for t in ((1, 2), (3, 4))]]
is giving me
[(3, 4), (3, 4)]

The equivalent using a generator expression:

List comps were originally designed to be equivalent to for loops with
nested for loops and if blocks. Generator expressions are know to be
slightly different and *not* exactly equivalent due to the new local
namespace.
[f() for f in (lambda: t for t in ((1, 2), (3, 4)))]
is giving me
[(1, 2), (3, 4)]

Since, when there is a difference, as above, the genex behavior is more
often the right or expected behavior (as above), Guido is considering
making the diference go away in 3.0 by making [stuff] == list((stuff)) (ie,
listcomp == list(genex)).

Terry Jan Reedy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,201
Latest member
KourtneyBe

Latest Threads

Top