[Python-Dev] Termination of two-arg iter()

Tim Peters tim.one@comcast.net
Sun, 14 Jul 2002 16:42:13 -0400


[Barry]
> I think it would be fine to leave the situation as is
> (i.e. undefined).

As is, the PEP makes promises the implementation doesn't keep, so that part
isn't fine.  If we don't want to change the implementation(s), then that
part of the PEP should be changed to, e.g.,

      Resolution:  once StopIteration is raised, the effect of calling
      it.next() again isn't defined by the iteration protocol.  Code
      manipulating arbitrary iterators must therefore not rely on any
      particular behavior in this case.  For example, a given iterator
      may choose to raise StopIteration again, raise some other
      exception, return a value, play the theme music for Monty Python's
      Flying Circus, or decline to define the effect.

That's a start.  Then another round of decisions needs to be made for each
iterator Python supplies:  should it define the effect or not, and if so
what is it, or if not should it be explicit about not defining it?
Generators already do:

    If an unhandled exception-- including, but not limited to,
    StopIteration --is raised by, or passes through, a generator function,
    then the exception is passed on to the caller in the usual way, and
    subsequent attempts to resume the generator function raise
    StopIteration.

The current docs for two-argument iter() also tell the truth about what
happens.  I'm not sure anything else does, unless we take the absence of
docs as implying that an iterator explicitly refuses to define what happens.

So from Fred's POV <wink>, it would be easier to change the implementations
to match the current PEP wording.

I'll note one pragmatic concern.  This idiom is becoming mildly popular:

for x in someiterator:
    if is_boundary_marker(x):
        break
    else:
        do_something_with(x)

followed by (in time, not necessarily in a physically distinct loop):

for x in someiterator:
    # and we expect this to pick up where the last loop left off

If StopIteration isn't a sink state, this falls under the "code manipulating
arbitrary iterators must therefore not rely on any particular behavior in
this case" warning in the reworded docs.  That is, if the first loop
terminated via iterator exhaustion, the obvious intent is that the second
loop never enter its body.  This is reliably true if and only if
StopIteration is guaranteed to be a sink state.  The more I ponder that, the
more I'm inclined to believe that the PEP made the right decision the first
time:  guaranteeing *something* makes it possible to write a larger class of
generic code.