[Python-Dev] PEP 322: Reverse Iteration

Samuele Pedroni pedronis at bluewin.ch
Wed Nov 5 10:06:18 EST 2003


At 13:50 05.11.2003 +0000, Moore, Paul wrote:
>From: Jeremy Fincher [mailto:fincher.8 at osu.edu]
> > If this proposal could be satisfied by the simple definition:
> >
> > def reversed(seq):
> >     for i in xrange(len(seq)-1, -1, -1):
> >         yield seq[i]
> >
> > I wouldn't be for it.  The reason I'm +1 is because I want
> > a standard protocol for iterating in reverse over objects.
>
>The more I think about it, the less I see the need for reversed(). But I'm
>having a really difficult time articulating why.
>
>I don't see enough use cases for something which just reverses sequences,
>as above. I tend to loop over concrete sequences less and less these days,
>using iterators, generators, enumerate, itertools etc, far more. The simple
>reversed() above doesn't help at all there. OK, reversed([x]range) is useful,
>but as soon as an iterator-based irange existed, I'd use that for "forward"
>loops, and be most upset that reversed(irange) didn't work...
>
>Whenever I try to play with writing a reversed() which is more general than
>the code above, I get stuck because *something* needs reversing, but it's
>virtually never a sequence!
>
>So far, I've needed to reverse:
>
>     itertools.count()
>     itertools.zip()
>     enumerate()
>
>But this is all fairly incestuous - all I'm proving is that *if* you need
>reversed() on something other than a sequence, you can't do it without
>help from something (the object itself, or something else). But the cases
>*I* care about have been pre-existing Python objects, which Raymond is not
>proposing to extend in that way! (I can see that having the __reversed__
>protocol may help with user-defined objects, I just don't have such a need
>myself).

1) the problem is that reversed want to be simple and sweet, but general 
reverse iteration is not that simple.

2) itertools.count/ izip and enumerate produce iterators forgetting the 
original iterable so while nice

reversed(count(9))
reversed(enumerate([1,2,3]))

would require rather not straightforward mechanisms under the hood.

Either one write and introduce revenumerate , revcount revizip

OR one could make reversed also a functional allowing not only for

reversed(it) # it implements __reversed__ or it's a sequence

but also

reversed(count,9)
reversed(enumerate,[1,2,3])
reversed(izip,[1,2],[1,3])

[ the implementation would use some table to register the impl of all those 
behaviors], with possible behaviors:

def rev_count(n):
   while True:
     yield n
     n -= 1

def rev_izip(*iterables):
   iterables = map(reversed, iterables)
   while True:
     result = [i.next() for i in iterables]
     yield tuple(result)

def rev_enumerate(it):
     if hasattr(it, '__reversed__'):
         index = -1 # arbitrary but not totally meaningless :)
         for elem x.__reversed__():
             yield (index,x)
             index -= -1
     if hasattr(x, 'keys'):
         raise ValueError("mappings do not support reverse iteration")
     i = len(x)
     while i > 0:
         i -= 1
         yield (i,x[i])

rev_behavior = { enumerate: rev_enumerate, ... }

def reversed(*args):
   if len(args)>1:
     func = args[1]
     args = args[1:]
     rev_func = rev_behavior.get(func,None)
     if rev_func:
       for x in rev_func(args):
         yield x
     else:
       ... error
   else:
     ...

Whether this is for general consumption is another matter.

regards.























More information about the Python-Dev mailing list