[Python-ideas] Propagating StopIteration value
Oscar Benjamin
oscar.j.benjamin at gmail.com
Wed Oct 10 00:49:08 CEST 2012
On 9 October 2012 22:37, Terry Reedy <tjreedy at udel.edu> wrote:
> On 10/9/2012 11:34 AM, Serhiy Storchaka wrote:
>>
>> On 09.10.12 10:51, Greg Ewing wrote:
>>>
>>> Where we seem to disagree is on
>>> whether returning a value with StopIteration is part of the
>>> iterator protocol or the generator protocol.
Correct.
> Part of the iterator protocol is that .__next__ methods raise StopIteration
> to signal that no more objects will be yielded. A value can be attached to
> StopIteration, but it is irrelevant to it use as a 'done' signal. Any
> iterator .__next__ method. can raise or pass along
> StopIteration(something). Whether 'something' is even seen or not is a
> different question. The main users of iterators, for statements, ignore
> anything extra.
I know this isn't going anywhere right now but since it might one day
I thought I'd say that I considered how it could be different and the
best I came up with was:
def f():
return 42
yield
for x in f():
pass
else return_value:
# return_value = 42 if we get here
> If the generator stops by raising StopIteration instead of returning None,
> *that* StopIteration instance is passed along by the .__next__ wrapper.
> (This may be an implementation detail, but it is currently true.)
I'm wondering whether propagating or not propagating the StopIteration
should be a documented feature of some iterator-based functions or
should always be considered an implementation detail (i.e. undefined
language behaviour). Currently in Python 3.3 I guess that it is always
an implementation detail since the behaviour probably results from an
implementation that was written under the assumption that
StopIteration instances are interchangeable.
> Since filter takes a single iterable, it can be written like g3 and not
> catch the StopIteration of the corresponding iterator.
>
> def filter(pred, iterable):
> it = iter(iterable)
> while True:
> item = next(it)
> if pred(item):
> yield item
> # never reaches here, never returns None
>
> Map takes multiple iterables. In 2.x, map extended short iterables with None
> to match the longest. So it had to swallow StopIteration until it had
> collected one for each iterator. In 3.x, map stops at the first
> StopIteration, so it probably could be rewritten to not catch it. Whether it
> makes sense to do that is another question.
Thanks. That makes more sense now as I hadn't considered this
behaviour of map before.
Oscar
More information about the Python-ideas
mailing list