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

Delaney, Timothy tdelaney@avaya.com
Tue, 16 Jul 2002 11:10:16 +1000


> From: Aahz [mailto:aahz@pythoncraft.com]
> On Mon, Jul 15, 2002, Ka-Ping Yee wrote:
> >
> I also think that's the wrong question, given the nature of iterators;
> before you can ask that question, you need to demonstrate 
> that there is
> in fact a difference between an empty iterator and an 
> exhausted iterator.
> I think that you can't demonstrate that, but I'm certainly 
> willing to be
> convinced.

I think the definition that some people are using is:

An exhausted iterator is one for which StopIteration has already been
raised.

An empty iterator OTOH is one which will raise StopIteration the next time
next() is called. An iterator for an empty list is the simplest example of
this, although it should be applied to any iterator.

FWIW I think the "best" behaviour for iterators is that once an iterator
begins raising StopIteration is must continue to do so under any
circumstances.  Given than, I don't see a lot of point in distinguishing
between the two above cases.

One way this could be enforced (and the burden removed from iterator
writers) is to have iter() always returned a wrapper around an iterator:

class EnforcementIterator:

    __slots__ = ('iterator', 'exhausted',)

    def __init__(self, iterator):
        self.iterator = iterator
        self.exhausted = False

    # getattr, setattr, delattr delegate to self.iterator

    def __iter__(self):
        return self

    def next (self):

        if self.exhausted:
            raise StopIteration()

        try:
            return self.iterator.next()
        except StopIteration:
            self.exhausted = True
            raise

def iter (iterable):
    # testing for type - optimisation ;)
    if iterable instanceof EnforcementIterator:
        return iterable
    else:
        return EnforcementIterator(iterable.__iter__())

Tim Delaney