[Python-Dev] PEP 322: Reverse Iteration (original) (raw)

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