[Python-ideas] Add stop=exception option to next() (was Re: PEP 479 and take())

Terry Reedy tjreedy at udel.edu
Sun Dec 14 01:39:25 CET 2014

On 12/13/2014 5:36 PM, Antoine Pitrou wrote:
> On Sat, 13 Dec 2014 17:31:36 -0500
> Terry Reedy <tjreedy at udel.edu> wrote:
>> On 12/13/2014 7:45 AM, Oscar Benjamin wrote:
>>> On 10 December 2014 at 18:35, Guido van Rossum <guido at python.org> wrote:
>>> If you had both next() and take() to choose from then the only time
>>> next() would be preferable is when you want to leak StopIteration (a
>>> pattern that is now largely broken by PEP 479).
>>>> BTW did you know that next(iterator, default) returns default if the
>>>> iterator is exhausted? IOW this will never raise StopIteration. It's similar
>>>> to dict.get(key, default) or getattr(obj, attrname, default).
>>> I more often find that I want an error than a default value and of
>> I once proposed, either here or on python-list, and propose again,
>> that the signature of next be expanded so that the user could specify
>> the ending exception.  If possible, the stop object could either be an
>> exception class, which would be called with a generic message, or an
>> exception instance.
>> Then the awkward
>> try:
>>     item = next(it)
>> except StopIteration:
>>     raise ValueError('iterable must not be empty') from None
> I don't remember ever needing to write such code.

Others do, whenever the first item of an iterable needs special 
treatment.  And others *have* forgotten to catch StopIteration when 
calling next(it).

The code for reduce *is* written with such code.

 >>> from functools import reduce as r
 >>> r(lambda a, b: a+b, [])
Traceback (most recent call last):
   File "<pyshell#1>", line 1, in <module>
     r(lambda a, b: a+b, [])
TypeError: reduce() of empty sequence with no initial value

But the current equivalent code in the doc is buggy because it was not.

def reduce(function, iterable, initializer=None):
     it = iter(iterable)
     if initializer is None:
         value = next(it)
         value = initializer
     for element in it:
         value = function(value, element)
     return value

 >>> reduce(lambda a, b: a+b, [])
Traceback (most recent call last):
   File "C:\Programs\Python34\tem.py", line 11, in <module>
     reduce(lambda a, b: a+b, [])
   File "C:\Programs\Python34\tem.py", line 4, in reduce
     value = next(it)

The equivalent code now would be

     value = next(it)
except StopIteration:
     raise TypeError("reduce() of empty sequence with no initial value") 
from None


That a core developer would miss this illustrates to me why the addition 
is needed.  With this proposal, the correct equivalent would be

     value = next(it. stop=TypeError(
         "reduce() of empty sequence with no initial value"))

Terry Jan Reedy

More information about the Python-ideas mailing list