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

Tim Peters tim.one@comcast.net
Mon, 15 Jul 2002 02:18:32 -0400


[Oren Tirosh]
> Let's look at the options:  (are there any I forgot?)

We can always pretend the issue was never raised <0.9 wink>.

> 1. Define StopIteration as a sticky state.  People will write code that
> relies on this behavior.

You say that like it's a bad thing.

> The code will sometimes fail when run on 2.2.x or with certain existing
> user iterators.

But it's unlikely.  Most people stick to "for x in object:".  Those who
don't and rely on anything other than StopIteration being sticky are relying
on things explictly documented as not kosher.  If we did decide to enforce
the PEP, everything in the core that doesn't follow it is "a bug", and fixes
would get backported to the 2.2 line.

> It's probably the worst possible combination: you have to implement this
> in your iterators but you can't rely on it in code that may run on 2.2 or
> get iterators from libraries written before this was made into a
> requirement.

But it's already a requirement, according to the PEP.  Regardless of what
the PEP says or what things do, the safest course for users is not to
provoke the issue, i.e. never to write code that pokes an iterator after it
raises StopIteration.  All these choices become irrelevant to code doing so.
Your code may be an exception, but I'm sure the vast bulk of 2.2 code
already plays that way; for example, I doubt there's any code in the std
distribution that cares.

> 2. Leave things the way they are.  Since *almost* all builtin iterators
> behave this way people will continue to write code that relies on this.

It appears that more than half of the builtin iterators don't arrange to
make StopIteration sticky (sequence iterators and three flavors of dict
iterators and two-argument iter() iterators definitely do not; generator
iterators definitely do; Zope3 BTree iterators definitely do, but they're
not part of the Python core; the meta-rule here is that an iterator follows
the PEP if and only if I wrote it <wink>).

> It will silently fail for some builtin iterators and user iterators.

I'm not sure what "fail" means here.

> 3. Silently fix all iterators to be in a StopIteration sink state.  Even
> worse than #2. It looks like version 2.2 is going to live a long time.
> This will cause subtle and hard-to-find differences in behavior
> between 2.2 and 2.3.

We actively backport bugfixes to the 2.2 line.

> 4. Require iterators to raise an exception.  Places an extra burden on all
> iterator implementors.  A lot of existing code will suddenly be redefined
> as not kosher.

Raising any exception other than StopIteration is going to be a very hard
sell.

> 5. Leave it officially undefined but raise an exception for all
> or even some builtin iterators. Raising an exception for even one
> popular type (listiter)  would be more than enough to discourage
> code that relies on this behavior.

But not to stop it, and then users can't predict what will happen.

> No extra burden is placed on iterator implementers.

Didn't you just propose raising exceptions in "all or even some" builtin
iterators?  They weren't implemented by elves <wink>.

> No change to iterator protocol definition.

The only way to achieve that is your #1:  the current definition *is* sticky
state, albeit honored mostly in the breach.  If Guido doesn't want that now,
the definition has to change.

> No existing code is suddenly non-conforming.

Any existing code that relies on, or supplies, anything other than sticky
state is non-conforming right now.  You could turn that into "an advantage"
by flipping the claim to:

    Some non-conforming existing code would suddenly become officially
    blessed.