Peter Otten wrote: > To confuse a newbies and old hands alike, Bengt Richter wrote: > > > Need something more straightforward, e.g., a wrapped one-liner: > > > > >>> def guess(n=3): print ("You're right!", 'No more tries for > > >>> you!!!')[n-1 in > > ... (x for x in xrange(n) for t in [raw_input('Guess my name: > > ')=='Ben'] > > ... if not t or iter([]).next())] > > ... > > >>> guess() > > To make it a bit clearer, 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?
Very interesting. I'm not sure if the designers even considered this particular subtlety. Why it happens is pretty plain. In the generator expression case, the generator expression does propogate the StopIteration, but list() traps it. List comprehensions are internally treated as a for-loop (kind of), which doesn't trap StopIteration. Maybe it should. The list comprehension [ x for x in y ] is currently treated as equivalent to the following, with byte-code optimizations: . _ = [] . for x in y: . _.append(x) Perhaps it ought to be equivalent to: . _ = [] . try: . for x in y: . _.append(x) . except StopIteration: . pass However, I would guess the Python gods wouldn't approve of this use of StopIteration, and so would make no sacrifices to get it. Nevertheless, it seems likely to be how a list comprehension would behave in Python 3.0, so maybe we should do it. -- CARL BANKS -- http://mail.python.org/mailman/listinfo/python-list