From: exarkun on
On 02:58 pm, mal(a)egenix.com wrote:
>exarkun(a)twistedmatrix.com wrote:
>>On 08:45 am, tjreedy(a)udel.edu wrote:
>>>Tom Machinski wrote:
>>>>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()
>>>
>>>StopIteration is intended to be used only within the .__next__ method
>>>of iterators. The devs know that other 'off-label' use results in the
>>>inconsistency you noted, but their and my view is 'don't do that'.
>>
>>Which is unfortunate, because it's not that hard to get StopIteration
>>without explicitly raising it yourself and this behavior makes it
>>difficult to debug such situations.
>>
>>What's with this view, exactly? Is it just that it's hard to
>>implement
>>the more desirable behavior?
>
>I'm not exactly sure what you're asking for.
>
>The StopIteration exception originated as part of the for-loop
>protocol. Later on it was generalized to apply to generators
>as well.
>
>The reason for using an exception is simple: raising and catching
>exceptions is fast at C level and since the machinery for
>communicating exceptions up the call stack was already there
>(and doesn't interfere with the regular return values), this
>was a convenient method to let the upper call levels know
>that an iteration has ended (e.g. a for-loop 4 levels up the
>stack).
>
>I'm not sure whether that answers your question, but it's the
>reason for things being as they are :-)

I'm asking about why the behavior of a StopIteration exception being
handled from the `expression` of a generator expression to mean "stop
the loop" is accepted by "the devs" as acceptable. To continue your
comparison to for loops, it's as if a loop like this:

for a in b:
c

actually meant this:

for a in b:
try:
c
except StopIteration:
break

Note, I know *why* the implementation leads to this behavior. I'm
asking why "the devs" *accept* this.

Jean-Paul
From: Mel on
exarkun(a)twistedmatrix.com wrote:
[ ... ]
it's as if a loop like this:
>
> for a in b:
> c
>
> actually meant this:
>
> for a in b:
> try:
> c
> except StopIteration:
> break
>
> Note, I know *why* the implementation leads to this behavior. I'm
> asking why "the devs" *accept* this.

It's part of the price Python pays for letting people get their hands on the
controls. Consider also:

Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class dict2(dict):
.... def __getitem__ (self, key):
.... if key == 'fatal':
.... raise KeyError
....
>>> d = dict2()
>>> d['fatal'] = 'Hello, world!'
>>> print d['fatal']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __getitem__
KeyError
>>>


"KeyError when we just put the item into the dict?"
"Yep."


Mel.

>
> Jean-Paul


From: Terry Reedy on
On 12/14/2009 10:21 AM, exarkun(a)twistedmatrix.com wrote:

> I'm asking about why the behavior of a StopIteration exception being
> handled from the `expression` of a generator expression to mean "stop
> the loop" is accepted by "the devs" as acceptable.

Any unhandled exception within a loop stops the loop,
and the exception is passed to the surrounding code.

> To continue your
> comparison to for loops, it's as if a loop like this:
>
> for a in b:
> c
>
> actually meant this:
>
> for a in b:
> try:
> c
> except StopIteration:
> break

No it does not. If c raises any exception, the loop stops *and* the
exception is passed up to the surrounding code.

> Note, I know *why* the implementation leads to this behavior.

You do not seem to know what the behavior is.
Read what I wrote last night.

Terry Jan Reedy



From: exarkun on
On 06:00 pm, tjreedy(a)udel.edu wrote:
>On 12/14/2009 10:21 AM, exarkun(a)twistedmatrix.com wrote:
>>I'm asking about why the behavior of a StopIteration exception being
>>handled from the `expression` of a generator expression to mean "stop
>>the loop" is accepted by "the devs" as acceptable.
>
>Any unhandled exception within a loop stops the loop,
>and the exception is passed to the surrounding code.
>>To continue your
>>comparison to for loops, it's as if a loop like this:
>>
>>for a in b:
>>c
>>
>>actually meant this:
>>
>>for a in b:
>>try:
>>c
>>except StopIteration:
>>break
>
>No it does not.

No what does not? I said "It is as if". This is a hypothetical. I'm
not claiming this is the actual behavior of anything.
>>Note, I know *why* the implementation leads to this behavior.
>
>You do not seem to know what the behavior is.
>Read what I wrote last night.

Well, I'm a bit tired of this thread. Please disregard my question
above. I'm done here. Sorry for the confusion. Have a nice day.

Jean-Paul
From: Antoine Pitrou on
Le Mon, 14 Dec 2009 15:21:09 +0000, exarkun a écrit :
>
> I'm asking about why the behavior of a StopIteration exception being
> handled from the `expression` of a generator expression to mean "stop
> the loop" is accepted by "the devs" as acceptable.

It's not "accepted as acceptable", it's just a side effect of how various
means of iterating (including for loops and generators) are implemented
in CPython.
Seeing how it doesn't seem to prevent or promote any useful programming
idiom, there was no incentive to either 1) codify it as official spec or
2) change it.

In other words, it should be considered undefined behaviour, and perhaps
other Python implementations behave differently.

Regards

Antoine.