StopIteration in the if clause of a generator expression
Bengt Richter
bokr at oz.net
Fri Apr 1 16:14:20 EST 2005
On Fri, 01 Apr 2005 16:34:32 GMT, "Raymond Hettinger" <vze4rx4y at verizon.net> wrote:
>[Peter Otten]
>> a StopIteration raised in a generator expression
>> silently terminates that generator:
>>
>> >>> def stop(): raise StopIteration
>> ...
>> >>> list(i for i in range(10) if i < 5 or stop())
>> [0, 1, 2, 3, 4]
>>
>> In a list comprehension, on the other hand, it is propagated:
>>
>> >>> [i for i in range(10) if i < 5 or stop()]
>> Traceback (most recent call last):
>> File "<stdin>", line 1, in ?
>> File "<stdin>", line 1, in stop
>> StopIteration
>>
>> Is that an intentional difference?
>
>I would call it an unfortunate assymmetry -- one the never comes up unless
>you're up to no good ;-)
;-)
>
>In a way, both behave identically. They both raise StopIteration. In the case
>of the generator expression, that StopIteration is intercepted by the enclosing
>list() call. That becomes obvious if you write a pure python equivalent for
>list:
>
> def lyst(s):
> it = iter(s)
> result = []
> try:
> while 1:
> result.append(it.next())
> except StopIteration: # guess who trapped StopIter
> return result
>
>
I assumed that all standard sequence consumers (including list, of course) would intercept
the StopIteration of a sequence given them in the form of a generator expression, so your
lyst example would have an analogue for other sequence consumers as well, right?
I.e., there's not a hidden list(genex) in those others I would hope ;-)
E.g., "in" in my toy exposed more clearly, using Peter's stop:
>>> def show(x): print x,; return x
...
>>> def stop(): raise StopIteration
...
>>> 2 in (x for x in xrange(5) if show(x)<4 or stop())
0 1 2
True
>>> 7 in (x for x in xrange(5) if show(x)<4 or stop())
0 1 2 3 4
False
BTW I notice that this also nicely shortcuts when the 2 is found.
Regards,
Bengt Richter
More information about the Python-list
mailing list