Pre-PEP: reverse iteration methods

Raymond Hettinger vze4rx4y at
Wed Sep 24 20:18:03 CEST 2003

> >Abstract
> >========
> >
> >This proposal is to extend the API of several sequence types
> >to include methods for iterating over the sequence in reverse.

[Christos TZOTZIOY Georgiou]
> -0
> I believe this should be a function in itertools.
> For indexable sequences, a little modification of itertools.islice would
> do the trick, since it can't at the moment; it's designed for forward
> iteration.
> Helpful error messages:
> >>> itertools.islice(lst, len(lst)-1, -1, -1)
> ValueError: Stop argument must be an integer or None.
> >>> itertools.islice(lst, len(lst)-1, None, -1)
> ValueError: Step must be one or larger for islice().
> For non-indexable sequences (eg a file object), things get hairier, but
> given enough memory, it's not hard.

Here's a quick and dirty implementation of your idea (kept separate
from islice for clarity).   On the plus side, it is somewhat clean and
easy to use.  On the minus side:
  * It's slower than custom iterator methods
  * It behaves badly with infinite iterators as inputs
  * For non-indexables, it silently transitions into a
     non-lazy, memory intensive mode with a long
     delay on the first call.  In my opinion, this defeats
     the purpose of using iterators in the first place.

def ireverse(obj):
    assert not hasattr(obj, 'keys')
        for i in xrange(len(obj)-1, -1, -1):
            yield obj[i]
    except (AttributeError, TypeError):
        x = list(obj)   # XXX fails with infinite iterators
        for elem in x:
            yield elem

for i in ireverse(xrange(5)):
    print i

for c in ireverse('abcde'):
    print c

for elem in ireverse(['atom', 'beta', 'curry']):
    print elem

for line in ireverse(file('/autoexec.bat')):
    print line.rstrip()

for x in reverse(itertools.count()):
    # Never gets here and Python dies with a MemoryError
    # from the infinite loop

Raymond Hettinger

More information about the Python-list mailing list