From: Tom Machinski on
In most cases, `list(generator)` works as expected. Thus,
`list(<generator expression>)` is generally equivalent to `[<generator
expression>]`.

Here's a minimal case where this equivalence breaks, causing a serious
and hard-to-detect bug in a program:

>>> def sit(): raise StopIteration()
...
>>> [f() for f in (lambda:1, sit, lambda:2)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in sit
StopIteration
>>> list(f() for f in (lambda:1, sit, lambda:2))
[1]

I was bitten hard by this inconsistency when sit() was returning the
idiom `(foo for foo in bar if foo.is_baz()).next()`. The nonexistence
of a foo with is_baz() True in that query raises an exception as
designed, which expresses itself when I use the list comprehension
version of the code above; the generator version muffles the error and
silently introduces a subtle, confusing bug: `lambda:2` is never
reached, and a truncated list of 1 element (instead of 3) is
"successfully" generated..

Just wondered what you guys think,

-- Tom
From: Benjamin Kaplan on
On Sat, Dec 12, 2009 at 7:15 PM, Tom Machinski <tom.machinski(a)gmail.com> wrote:
> In most cases, `list(generator)` works as expected. Thus,
> `list(<generator expression>)` is generally equivalent to `[<generator
> expression>]`.
>

Actually, it's list(generator) vs. a list comprehension. I agree that
it can be confusing, but Python considers them to be two different
constructs.

>>> list(xrange(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [xrange(10)]
[xrange(10)]



> Here's a minimal case where this equivalence breaks, causing a serious
> and hard-to-detect bug in a program:
>
>  >>> def sit(): raise StopIteration()
>  ...
>  >>> [f() for f in (lambda:1, sit, lambda:2)]
>  Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
>    File "<stdin>", line 1, in sit
>  StopIteration
>  >>> list(f() for f in (lambda:1, sit, lambda:2))
>  [1]
>
> I was bitten hard by this inconsistency when sit() was returning the
> idiom `(foo for foo in bar if foo.is_baz()).next()`. The nonexistence
> of a foo with is_baz() True in that query raises an exception as
> designed, which expresses itself when I use the list comprehension
> version of the code above; the generator version muffles the error and
> silently introduces a subtle, confusing bug: `lambda:2` is never
> reached, and a truncated list of 1 element (instead of 3) is
> "successfully" generated..
>
> Just wondered what you guys think,
>
>  -- Tom
> --
> http://mail.python.org/mailman/listinfo/python-list
>
From: Ned Deily on
In article
<ec96e1390912121653w56c3dbe3p859a7b979026bf47(a)mail.gmail.com>,
Benjamin Kaplan <benjamin.kaplan(a)case.edu> wrote:
> On Sat, Dec 12, 2009 at 7:15 PM, Tom Machinski <tom.machinski(a)gmail.com>
> wrote:
> > In most cases, `list(generator)` works as expected. Thus,
> > `list(<generator expression>)` is generally equivalent to `[<generator
> > expression>]`.
> Actually, it's list(generator) vs. a list comprehension. I agree that
> it can be confusing, but Python considers them to be two different
> constructs.
>
> >>> list(xrange(10))
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> >>> [xrange(10)]
> [xrange(10)]

That's not a list comprehension, that's a list with one element.

>>> [x for x in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

<CrocodileDundee> Now *that's* a list comprehension. </CrocodileDundee>

--
Ned Deily,
nad(a)acm.org

From: Benjamin Kaplan on
On Sat, Dec 12, 2009 at 9:01 PM, Ned Deily <nad(a)acm.org> wrote:
> In article
> <ec96e1390912121653w56c3dbe3p859a7b979026bf47(a)mail.gmail.com>,
>  Benjamin Kaplan <benjamin.kaplan(a)case.edu> wrote:
>> On Sat, Dec 12, 2009 at 7:15 PM, Tom Machinski <tom.machinski(a)gmail.com>
>> wrote:
>> > In most cases, `list(generator)` works as expected. Thus,
>> > `list(<generator expression>)` is generally equivalent to `[<generator
>> > expression>]`.
>> Actually, it's list(generator) vs. a list comprehension. I agree that
>> it can be confusing, but Python considers them to be two different
>> constructs.
>>
>> >>> list(xrange(10))
>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>> >>> [xrange(10)]
>> [xrange(10)]
>
> That's not a list comprehension, that's a list with one element.
>
>>>> [x for x in xrange(10)]
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>
> <CrocodileDundee> Now *that's* a list comprehension. </CrocodileDundee>
>

I know. But the OP was wondering why list(<generator expression>) was
behaving differently than [<generator-expression>] and I was pointing
out that list comprehensions are considered their own syntax- the list
comprehension [x for x in xrange(10)] is different than [(x for x in
xrange(10)].
> --
>  Ned Deily,
>  nad(a)acm.org
>
> --
> http://mail.python.org/mailman/listinfo/python-list
>
From: Ned Deily on
In article <nad-8CDB63.18012412122009(a)news.gmane.org>,
Ned Deily <nad(a)acm.org> wrote:

> In article
> <ec96e1390912121653w56c3dbe3p859a7b979026bf47(a)mail.gmail.com>,
> Benjamin Kaplan <benjamin.kaplan(a)case.edu> wrote:
> > On Sat, Dec 12, 2009 at 7:15 PM, Tom Machinski <tom.machinski(a)gmail.com>
> > wrote:
> > > In most cases, `list(generator)` works as expected. Thus,
> > > `list(<generator expression>)` is generally equivalent to `[<generator
> > > expression>]`.
> > Actually, it's list(generator) vs. a list comprehension. I agree that
> > it can be confusing, but Python considers them to be two different
> > constructs.
> >
> > >>> list(xrange(10))
> > [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> > >>> [xrange(10)]
> > [xrange(10)]
>
> That's not a list comprehension, that's a list with one element.
>
> >>> [x for x in xrange(10)]
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>
> <CrocodileDundee> Now *that's* a list comprehension. </CrocodileDundee>

Which is not quite the point Benjamin was trying to make - sorry!

Consulting the adjacent sections on "List displays" and "Generator
expressions" in the Language Reference:

http://docs.python.org/reference/expressions.html#list-displays

for generator expressions "the parentheses can be omitted on calls with
only one argument " but the expressions in a list_comprehension are not
in a call context. So there is no ambiguity: [<generator expression>]
requires parens around the generator expression and that list display
produces a list with one element as Benjamin points out.

--
Ned Deily,
nad(a)acm.org