Update PEP based on discussion on comp.lang.python:
* reversed() is being preferred to ireverse() as the best name. * the sample implementation now shows a check for a custom reverse method and a guard against being applied to a mapping. * added sample output for enumerate.__reversed__ to show an example of how a custom reverse method would work * explained why the function is proposed as a builtin. * expanded a couple for the real world use cases to show what the replacement code would look like. * improved markup so that the function names get italicized.
This commit is contained in:
parent
36e7a69be3
commit
a232b370a0
56
pep-0322.txt
56
pep-0322.txt
|
@ -46,35 +46,38 @@ does arise regularly in practice. See `Real World Use Cases`_ below.
|
|||
Proposal
|
||||
========
|
||||
|
||||
Add a builtin function called *ireverse()* that makes a reverse
|
||||
Add a builtin function called *reversed()* that makes a reverse
|
||||
iterator over sequence objects that support __getitem__() and
|
||||
__len__().
|
||||
|
||||
The above examples then simplify to::
|
||||
|
||||
for i in ireverse(xrange(n)):
|
||||
for i in reversed(xrange(n)):
|
||||
print seqn[i]
|
||||
|
||||
::
|
||||
|
||||
for elem in ireverse(seqn):
|
||||
for elem in reversed(seqn):
|
||||
print elem
|
||||
|
||||
The core idea is that the clearest, least error-prone way of specifying
|
||||
reverse iteration is to specify it in a forward direction and then say
|
||||
*ireverse*.
|
||||
*reversed*.
|
||||
|
||||
The implementation could be as simple as::
|
||||
|
||||
def ireverse(x):
|
||||
def reversed(x):
|
||||
try:
|
||||
return x.__reversed__()
|
||||
except AttributeError:
|
||||
pass
|
||||
if hasattr(x, "has_key"):
|
||||
raise ValueError("mappings do not support reverse iteration")
|
||||
i = len(x)
|
||||
while i > 0:
|
||||
i -= 1
|
||||
yield x[i]
|
||||
|
||||
If *x* is a mapping, the implementation should return a ValueError with
|
||||
a message noting that reverse iteration is undefined for mappings.
|
||||
|
||||
No language syntax changes are needed. The proposal is fully backwards
|
||||
compatible.
|
||||
|
||||
|
@ -82,7 +85,7 @@ compatible.
|
|||
Alternative Method Names
|
||||
========================
|
||||
|
||||
* *backwards* -- more pithy, less explicit
|
||||
* *ireverse* -- uses the itertools naming convention
|
||||
* *inreverse* -- no one seems to like this one except me
|
||||
|
||||
The name *reverse* is not a candidate because it duplicates the name
|
||||
|
@ -92,15 +95,18 @@ of the list.reverse() which mutates the underlying list.
|
|||
Custom Reverse
|
||||
==============
|
||||
|
||||
Objects may optionally provide an *__ireverse__* method that returns
|
||||
Objects may optionally provide a *__reversed__* method that returns
|
||||
a custom reverse iterator.
|
||||
|
||||
This allows reverse() to be applied to objects that do not have
|
||||
This allows *reverse()* to be applied to objects that do not have
|
||||
__getitem__() and __len__() but still have some useful way of
|
||||
providing reverse iteration.
|
||||
|
||||
Using this protocol, enumerate() can be extended to support reversal
|
||||
whenever the underlying iterator supports it also.
|
||||
For example, using this protocol, *enumerate()* can be extended to
|
||||
support reversal whenever the underlying iterator supports it also::
|
||||
|
||||
>>> list(reversed(enumerate("abc")))
|
||||
[(2, 'c'), (1, 'b'), (0, 'a')]
|
||||
|
||||
|
||||
Real World Use Cases
|
||||
|
@ -123,6 +129,8 @@ library and comments on why reverse iteration was necessary:
|
|||
lower-level orderings. A forward version of this algorithm is
|
||||
possible; however, that would complicate the rest of the heap code
|
||||
which iterates over the underlying list in the opposite direction.
|
||||
The replacement code ``for i in reversed(xrange(n//2))`` makes
|
||||
clear the range covered and how many iterations it takes.
|
||||
|
||||
* mhlib.test() uses::
|
||||
|
||||
|
@ -143,7 +151,7 @@ library and comments on why reverse iteration was necessary:
|
|||
elements from an ever diminishing pool. In fact, the algorithm can
|
||||
be run in a forward direction but is less intuitive and rarely
|
||||
presented that way in literature. The replacement code
|
||||
``for i in ireverse(xrange(1, len(x)))`` is much easier
|
||||
``for i in reversed(xrange(1, len(x)))`` is much easier
|
||||
to verify visually.
|
||||
|
||||
* rfc822.Message.__delitem__() uses::
|
||||
|
@ -160,17 +168,17 @@ Active Alternative
|
|||
==================
|
||||
|
||||
A simpler, but limited alternative is to create a builtin that takes
|
||||
the same arguments as range() but returns a reverse iterator over the
|
||||
range. The idea is that much of the benefit of ireverse() comes
|
||||
the same arguments as *range()* but returns a reverse iterator over the
|
||||
range. The idea is that much of the benefit of *reversed()* comes
|
||||
reducing the intellectual effort it takes to express the arguments for
|
||||
[x]range() when going backwards. A good name is needed for this
|
||||
alternative -- revrange() is cleanest so far.
|
||||
alternative -- *revrange()* is cleanest so far.
|
||||
|
||||
|
||||
Rejected Alternative
|
||||
====================
|
||||
Rejected Alternatives
|
||||
=====================
|
||||
|
||||
Several variants were submitted that attempted to apply ireverse()
|
||||
Several variants were submitted that attempted to apply *reversed()*
|
||||
to all iterables by running the iterable to completion, saving the
|
||||
results, and then returning a reverse iterator over the results.
|
||||
While satisfying some notions of full generality, running the input
|
||||
|
@ -178,6 +186,14 @@ to the end is contrary to the purpose of using iterators
|
|||
in the first place. Also, a small disaster ensues if the underlying
|
||||
iterator is infinite.
|
||||
|
||||
Putting the function in another module or attaching it to a type object
|
||||
is not being considered. Like its cousins, *zip()* and *enumerate()*,
|
||||
the function needs to be directly accessible in daily programming. Each
|
||||
solves a basic looping problem: lock-step iteration, loop counting, and
|
||||
reverse iteration. Requiring some form of dotted access would interfere
|
||||
with their simplicity, daily utility, and accessibility. They are core
|
||||
looping constructs, independent of any one application domain.
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
|
Loading…
Reference in New Issue