Updated to reflect comments on comp.lang.python.
This commit is contained in:
parent
c884456428
commit
996d620420
60
pep-0322.txt
60
pep-0322.txt
|
@ -29,16 +29,15 @@ error prone, unnatural, and not especially readable::
|
||||||
|
|
||||||
One other current approach involves reversing a list before iterating
|
One other current approach involves reversing a list before iterating
|
||||||
over it. That technique wastes computer cycles, memory, and lines of
|
over it. That technique wastes computer cycles, memory, and lines of
|
||||||
code. Also, it only works with lists (strings, for example, do not
|
code::
|
||||||
define a reverse method)::
|
|
||||||
|
|
||||||
rseqn = list(seqn)
|
rseqn = list(seqn)
|
||||||
rseqn.reverse()
|
rseqn.reverse()
|
||||||
for value in rseqn:
|
for value in rseqn:
|
||||||
print value
|
print value
|
||||||
|
|
||||||
Extending slicing minimizes the code overhead but does nothing for
|
Extending slicing is a third approach that minimizes the code overhead
|
||||||
memory efficiency, beauty, or clarity.
|
but does nothing for memory efficiency, beauty, or clarity.
|
||||||
|
|
||||||
Reverse iteration is much less common than forward iteration, but it
|
Reverse iteration is much less common than forward iteration, but it
|
||||||
does arise regularly in practice. See `Real World Use Cases`_ below.
|
does arise regularly in practice. See `Real World Use Cases`_ below.
|
||||||
|
@ -109,6 +108,9 @@ library and comments on why reverse iteration was necessary:
|
||||||
. . .
|
. . .
|
||||||
del _exithandlers
|
del _exithandlers
|
||||||
|
|
||||||
|
Note, if the order of deletion is important, then the first form
|
||||||
|
is still needed.
|
||||||
|
|
||||||
* difflib.get_close_matches() uses::
|
* difflib.get_close_matches() uses::
|
||||||
|
|
||||||
result.sort() # Retain only the best n.
|
result.sort() # Retain only the best n.
|
||||||
|
@ -149,18 +151,15 @@ library and comments on why reverse iteration was necessary:
|
||||||
* platform._dist_try_harder() uses
|
* platform._dist_try_harder() uses
|
||||||
``for n in range(len(verfiles)-1,-1,-1)`` because the loop deletes
|
``for n in range(len(verfiles)-1,-1,-1)`` because the loop deletes
|
||||||
selected elements from *verfiles* but needs to leave the rest of
|
selected elements from *verfiles* but needs to leave the rest of
|
||||||
the list intact for further iteration. This use case could be
|
the list intact for further iteration.
|
||||||
addressed with *itertools.ifilter()* but would require the
|
|
||||||
selection predicate to be in a *lambda* expression. The net
|
|
||||||
result is less clear and readable than the original. A better
|
|
||||||
reformulation is to replace the first line with the proposed
|
|
||||||
method.
|
|
||||||
|
|
||||||
* random.shuffle() uses ``for i in xrange(len(x)-1, 0, -1)`` because
|
* random.shuffle() uses ``for i in xrange(len(x)-1, 0, -1)`` because
|
||||||
the algorithm is most easily understood as randomly selecting
|
the algorithm is most easily understood as randomly selecting
|
||||||
elements from an ever diminishing pool. In fact, the algorithm can
|
elements from an ever diminishing pool. In fact, the algorithm can
|
||||||
be run in a forward direction but is less intuitive and rarely
|
be run in a forward direction but is less intuitive and rarely
|
||||||
presented that way in literature.
|
presented that way in literature. The replacement code
|
||||||
|
``for i in xrange(1, len(x)).iter_backwards()`` is much easier
|
||||||
|
to mentally verify.
|
||||||
|
|
||||||
* rfc822.Message.__delitem__() uses::
|
* rfc822.Message.__delitem__() uses::
|
||||||
|
|
||||||
|
@ -172,23 +171,32 @@ library and comments on why reverse iteration was necessary:
|
||||||
underlying list is altered during iteration.
|
underlying list is altered during iteration.
|
||||||
|
|
||||||
|
|
||||||
Rejected Alternative Ideas
|
Alternative Ideas
|
||||||
==========================
|
=================
|
||||||
|
|
||||||
* Add a builtin function, *reverse()* which calls a magic method,
|
* Add a builtin function, *riter()* which calls a magic method,
|
||||||
__riter__. I see this as more overhead for no additional benefit.
|
*__riter__*. I see this as more overhead for no additional benefit.
|
||||||
|
|
||||||
* Add a builtin function, *reverse()* which does the above, and
|
* Several variants were submitted that provided fallback behavior
|
||||||
if *__riter__* is not found, constructs its own using
|
when *__riter__* is not defined:
|
||||||
*__getitem__*, and if *__getitem__* is not found, builds a list
|
|
||||||
from *__iter__* and returns a reverse iterator over the new list.
|
- fallback to: ``for i in xrange(len(obj)-1,-1,-1): yield obj[i]``
|
||||||
The advantage is that one function takes care of almost everything
|
- fallback to: ``for i in itertools.count(): yield[obj[-i]]``
|
||||||
that is potentially reversible. A disadvantage is that it can
|
- fallback to: ``tmp=list(obj); tmp.reverse(); return iter(tmp)``
|
||||||
invisibility slip in to a low performance mode (in terms of time
|
|
||||||
and memory) which would be more visible with an explicit
|
All of these attempt to save implementing some object methods at the
|
||||||
``list(obj).reverse()``. Another problem is that *__getitem__*
|
expense of adding a new builtin function and of creating a new magic
|
||||||
is also used in mappings as well as sequences and that could lead
|
method name.
|
||||||
to bizarre results.
|
|
||||||
|
The approaches using *__getitem__()* are slower than using a custom
|
||||||
|
method for each object. Also, the *__getitem__()* variants produce
|
||||||
|
bizarre results when applied to mappings.
|
||||||
|
|
||||||
|
All of the variants crash when applied to an infinite iterator.
|
||||||
|
|
||||||
|
The last variant can invisibly slip into a low performance mode
|
||||||
|
(in terms of time and memory) which could be made more visible with
|
||||||
|
an explicit ``list(obj).reverse()``.
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
|
|
Loading…
Reference in New Issue