PEP 322: Reverse Iteration (second revision, please comment)

Alex Martelli aleax at aleax.it
Thu Oct 30 05:46:45 EST 2003


Raymond Hettinger wrote:
   ...
> * the sample implementation now clearly shows a check for a custom
>   reverse method and a guard against being applied to a mapping.

SyntaxError: 'return' with argument inside generator

So presumably said check must be recoded in the PEP as:

    try:
        customiter = x.__reversed__
    except AttributeError:
        pass
    else:
        for i in customiter():
            yield i
        return

Yeah, sometimes it WOULD be nice if "return with argument inside
generator" automagically expanded to "for ...: yield / return".


> Also, please take a look at the revrange() alternative to see if you
> prefer it or not.

It would deal more directly with about half of my use cases but
less directly with the other half, so that's roughly a wash.  But
having revrange return a list would just perpetuate the minor wart
that range has now become, and having it NOT return a list (rather
an iterator) would violate the principle of Least Surprise wrt range.

A built-in iterator irange -- with an optional "reverse=" argument,
just like the very useful one you recently added to list.sort -- would be
just as useful as revrange for the latter's use cases, AND be very handy to
me in many more cases in which I currently use xrange and cringe each and
every time.  Plus, specifically, I have some uses cases where:

    if mustbereversed(...):
       seq = xrange(N-1, -1, -1)
    else:
       seq = xrange(N)
    for item in seq:
       ...

and those would get a somewhat minor benefit from either reverse OR
revrange, since the if/else to prepare seq would still be there,
albeit more readable along one of the two branches.  However, for this
kind of use case, an irange with an optional reverse= would be PERFECT:

    for item in irange(N, reverse=mustbereversed(...)):
       ...

now THAT would be blissful indeed.

I opine irange-w-opt-parm would be by far the best solution.  E.g.,
in your use case from heapq.heapify, just about custommade for
revrange, in my opinion the three possibilities:
    for i in reversed(xrange(n//2)):
       ...
    for i in revrange(n//2):
       ...
    for i in irange(n//2, reverse=True):
       ...
are just about equivalent -- the concision of revrange is a very
minor benefit even here.  The vastly wider usecases of irange might
in fact even let us slowly and gradually start "discouraging" the
use of range and xrange -- that will be the day... I've pined for
an irange even since the iterator protocol appeared.  And the use
of the "reverse=True" idiom will be widespread and habitual anyway
thanks to the fact that it's present in list.sort as well now.

(_and_, IMHO, irange has 100% appropriateness as a builtin, given
that it would/should soon become ***one of the most widely used
constructs in Python*** -- FAR more than revrange or reversed...!).


Alex





More information about the Python-list mailing list