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

Paul Moore p.f.moore at gmail.com
Fri Nov 21 17:14:58 CET 2014


On 21 November 2014 15:58, Steven D'Aprano <steve at pearwood.info> wrote:
>> >     def izip(iterable1, iterable2):
>> >         it1 = iter(iterable1)
>> >         it2 = iter(iterable2)
>> >         while True:
>> >             v1 = next(it1)
>> >             v2 = next(it2)
>> >             yield v1, v2
>>
>> Is it obvious to every user that this will consume an element from
>> it1, then silently terminate if it2 no longer has any content?
>
> "Every user"? Of course not. But it should be obvious to those who think
> carefully about the specification of zip() and what is available to
> implement it.
>
> zip() can't detect that the second argument is empty except by calling
> next(), which it doesn't do until after it has retrieved a value from
> the first argument. If it turns out the second argument is empty, what
> can it do with that first value? It can't shove it back into the
> iterator. It can't return a single value, or pad it with some sentinel
> value (that's what izip_longest does). Since zip() is documented as
> halting on the shorter argument, it can't raise an exception. So what
> other options are there apart from silently consuming the value?

Interestingly, although I said "yes, it's obvious", I'd missed this
subtlety. But I don't consider it "unexpected" or a "gotcha", just
subtle. I certainly don't consider it to be the *wrong* behaviour - on
the contrary, I'd be more surprised to get a RuntimeError when the
second iterator was shorter.

What I understand to be the recommended alternative:

    def izip(iterable1, iterable2):
        it1 = iter(iterable1)
        it2 = iter(iterable2)
        while True:
            try:
                # Is it OK to cover both statements with one try...except?
                # I think it should be, but it's a pattern I try to avoid
                v1 = next(it1)
                v2 = next(it2)
            except StopIteration:
                return
           yield v1, v2

looks less obvious to me, and obscures the intent a little.

(Note that I understand this is only one example and that others
present a much more compelling case in favour of the explicit return
form)

Paul


More information about the Python-Dev mailing list