[Python-ideas] PEP 479: Change StopIteration handling inside generators

Chris Angelico rosuav at gmail.com
Wed Nov 19 23:57:43 CET 2014


On Thu, Nov 20, 2014 at 9:46 AM, Terry Reedy <tjreedy at udel.edu> wrote:
> On 11/19/2014 11:24 AM, Chris Angelico wrote:
>> The distinction in __next__ is between returning something and raising
>> something. The distinction in a generator is between "yield" and
>> "return".
>
>
> Which, as I said a week ago, is why there is no need for "raise
> StopIteration" in a generator function.  The doc clearly states the limited
> intended use of StopIteration.
> '''
> exception StopIteration
>     Raised by built-in function next() and an iterator‘s __next__() method
> to signal that there are no further items produced by the iterator.
> '''
> StopIteration is exposed so it can be raised in user coded __next__() and
> caught when using explicit next().  If it was only used for builtins and for
> loops, it would not need to be visible.
>
>> Why should a generator author have to be concerned about one
>> particular exception having magical meaning?
>
> I am not sure of your intent with this rhetorical (?) question.

Yes, rhetorical. Basically saying the same as you are: that
StopIteration is a part of __next__, not generators.

>> Imagine this scenario:
>>
>> def producer():
>>      """Return user input, or raise KeyboardInterrupt"""
>>      return input("Enter the next string: ")
>
> The prompt should be "Enter the next string or hit ^C to quit: ".

Yeah, the point is about its interaction with the rest of the program,
not the human.

>> def consumer():
>>      """Process the user's input"""
>>      while True:
>>          try:
>>              command = producer()
>>          except KeyboardInterrupt:
>>              break
>>          dispatch(command)
>
>
>> Okay, now let's make a mock producer:
>>
>> strings = ["do stuff","do more stuff","blah blah"]
>> def mock_producer()
>>      if strings: return strings.pop(0)
>>      raise KeyboardInterrupt
>
>
>> That's how __next__ works, only with a different exception, and I
>> think people would agree that this is NOT a good use of
>> KeyboardInterrupt.
>
>
> It is avoidable because the return type of producer is limited to strings.
> Therefore, producer could (and perhaps should) itself catch
> KeyboardInterrupt and return None, which is intended for such use. Consumer
> would then be simplified by replacing 3 lines with "if command is None:
> break".

Sure it does. But suppose it does some parsing on the string first,
and that parsing might return literally any object. The structure of
the program is the same, but now it really does need to signal "no
more stuff" in some way other than return value.

Just trying to concoct a situation similar to generators/for loops,
using a different exception. I'm fairly sure there's no way to make
the above system seem truly plausible, because KeyboardInterrupt is a
bad exception for the purpose; but it's still broadly similar, and I
think the same applies: StopException should be *only* inside
__next__() and next(). Since generators can distinguish yield from
return, they don't need to distinguish return from raise.

ChrisA


More information about the Python-ideas mailing list