[Python-checkins] python/nondist/peps pep-0000.txt, 1.255, 1.256 pep-0322.txt, 1.5, 1.6

rhettinger at users.sourceforge.net rhettinger at users.sourceforge.net
Tue Oct 28 05:16:35 EST 2003


Update of /cvsroot/python/python/nondist/peps
In directory sc8-pr-cvs1:/tmp/cvs-serv12216

Modified Files:
	pep-0000.txt pep-0322.txt 
Log Message:
Update the reverse iteration pep to reflect comments from comp.lang.python,
from Guido, and from some on python-dev.



Index: pep-0000.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v
retrieving revision 1.255
retrieving revision 1.256
diff -C2 -d -r1.255 -r1.256
*** pep-0000.txt	27 Oct 2003 15:01:08 -0000	1.255
--- pep-0000.txt	28 Oct 2003 10:16:31 -0000	1.256
***************
*** 119,123 ****
   S   319  Python Synchronize/Asynchronize Block        Pelletier
   S   321  Date/Time Parsing and Formatting             Kuchling
!  S   322  Reverse Iteration Methods                    Hettinger
   S   323  Copyable Iterators                           Martelli
   S   754  IEEE 754 Floating Point Special Values       Warnes
--- 119,123 ----
   S   319  Python Synchronize/Asynchronize Block        Pelletier
   S   321  Date/Time Parsing and Formatting             Kuchling
!  S   322  Reverse Iteration                            Hettinger
   S   323  Copyable Iterators                           Martelli
   S   754  IEEE 754 Floating Point Special Values       Warnes
***************
*** 338,342 ****
   I   320  Python 2.4 Release Schedule                  Warsaw
   S   321  Date/Time Parsing and Formatting             Kuchling
!  S   322  Reverse Iteration Methods                    Hettinger
   SR  666  Reject Foolish Indentation                   Creighton
   S   754  IEEE 754 Floating Point Special Values       Warnes
--- 338,342 ----
   I   320  Python 2.4 Release Schedule                  Warsaw
   S   321  Date/Time Parsing and Formatting             Kuchling
!  S   322  Reverse Iteration                            Hettinger
   SR  666  Reject Foolish Indentation                   Creighton
   S   754  IEEE 754 Floating Point Special Values       Warnes

Index: pep-0322.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0322.txt,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** pep-0322.txt	28 Sep 2003 02:43:37 -0000	1.5
--- pep-0322.txt	28 Oct 2003 10:16:32 -0000	1.6
***************
*** 1,4 ****
  PEP: 322
! Title: Reverse Iteration Methods
  Version: $Revision$
  Last-Modified: $Date$
--- 1,4 ----
  PEP: 322
! Title: Reverse Iteration
  Version: $Revision$
  Last-Modified: $Date$
***************
*** 15,20 ****
  ========
  
! This proposal is to extend the API of several sequence types
! to include a method for iterating over the sequence in reverse.
  
  
--- 15,20 ----
  ========
  
! This proposal is to add a builtin function to support reverse
! iteration over sequences.
  
  
***************
*** 47,66 ****
  ========
  
! Add a method called *iterreverse()* to sequence objects that can
! benefit from it.  The above examples then simplify to::
  
!     for i in xrange(n).iterreverse():
          print seqn[i]
  
  ::
  
!     for elem in seqn.iterreverse():
          print elem
  
! The new protocol would be applied to lists, tuples, strings, and
! xrange objects.  It would not apply to unordered collections like
! dicts and sets.
  
! No language syntax changes are needed.
  
  
--- 47,81 ----
  ========
  
! Add a builtin function called *inreverse()* that makes a reverse
! iterator over sequence objects that support __getitem__() and
! __len__().
  
! The above examples then simplify to::
! 
!     for i in inreverse(xrange(n)):
          print seqn[i]
  
  ::
  
!     for elem in inreverse(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
! *inreverse*.
  
! The implementation could be as simple as::
! 
!     def inreverse(x):
!         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.
  
  
***************
*** 68,91 ****
  ========================
  
- * *iterbackwards* -- like iteritems() but somewhat long
  * *backwards* -- more pithy, less explicit
  * *ireverse* -- reminiscent of imap(), izip(), and ifilter()
  
  
! Other Issues
! ============
  
! * Should *tuple* objects be included?  In the past, they have been
!   denied some list like behaviors such as count() and index().  I
!   prefer that it be included.
  
! * Should *file* objects be included?  Implementing reverse iteration
!   may not be easy though it would be useful on occasion.  I think
!   this one should be skipped.
  
! * Should *enumerate* objects be included?  They can provide reverse
!   iteration only when the underlying sequences support *__len__*
!   and reverse iteration.  I think this can be saved for another
!   day if the need arises.
  
  
--- 83,102 ----
  ========================
  
  * *backwards* -- more pithy, less explicit
  * *ireverse* -- reminiscent of imap(), izip(), and ifilter()
  
  
! Custom Reverse
! ==============
  
! Objects may optionally provide an *__inreverse__* method that returns
! a custom reverse iterator.
  
! 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.
  
  
***************
*** 102,138 ****
              . . .
  
!   The application dictates the need to run exit handlers in the
!   reverse order they were built.  The ``while alist: alist.pop()``
!   form is readable and clean; however, it would be slightly faster
!   and clearer with::
! 
!     for func, target, kargs in _exithandlers.iterreverse():
!         . . .
!     del _exithandlers
! 
!   Note, if the order of deletion is important, then the first form
!   is still needed.
! 
! * difflib.get_close_matches() uses::
! 
!     result.sort()           # Retain only the best n.
!     result = result[-n:]    # Move best-scorer to head of list.
!     result.reverse()        # Strip scores.
!     return [x for score, x in result]
! 
!   The need for reverse iteration arises from a requirement to return
!   a portion of a sort in an order opposite of the sort criterion.  The
!   list comprehension is incidental (the third step of a Schwartzian
!   transform).  This particular use case can met with extended slicing,
!   but the code is somewhat unattractive, hard to visually verify,
!   and difficult for beginners to construct::
! 
!       result.sort()
!       return [x for score, x in result[:-n-1:-1]]
! 
!   The proposed form is much easier to construct and verify::
! 
!       result.sort()
!       return [x for score, x in result[-n:].iterreverse()]
  
  * heapq.heapify() uses ``for i in xrange(n//2 - 1, -1, -1)`` because
--- 113,118 ----
              . . .
  
!   In this application popping is required, so the new function would
!   not help.
  
  * heapq.heapify() uses ``for i in xrange(n//2 - 1, -1, -1)`` because
***************
*** 161,166 ****
    be run in a forward direction but is less intuitive and rarely
    presented that way in literature.  The replacement code
!   ``for i in xrange(1, len(x)).iterreverse()`` is much easier
!   to mentally verify.
  
  * rfc822.Message.__delitem__() uses::
--- 141,146 ----
    be run in a forward direction but is less intuitive and rarely
    presented that way in literature.  The replacement code
!   ``for i in inreverse(xrange(1, len(x)))`` is much easier
!   to verify visually.
  
  * rfc822.Message.__delitem__() uses::
***************
*** 174,203 ****
  
  
! Alternative Ideas
! =================
! 
! * Add a builtin function, *riter()* which calls a magic method,
!   *__riter__*.  I see this as more overhead for no additional benefit.
! 
! * Several variants were submitted that provided fallback behavior
!   when *__riter__* is not defined:
! 
!   - fallback to:  ``for i in xrange(len(obj)-1,-1,-1): yield obj[i]``
!   - fallback to:  ``for i in itertools.count(): yield obj[-i]``
!   - fallback to:  ``tmp=list(obj); tmp.reverse();  return iter(tmp)``
! 
!   All of these attempt to save implementing some object methods at the
!   expense of adding a new builtin function and of creating a new magic
!   method name.
! 
!   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 ``ro=list(obj); ro.reverse()``.
  
  
--- 154,167 ----
  
  
! Rejected Alternative
! ====================
  
! Several variants were submitted that attempted to apply inreverse()
! 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
! 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.
  
  





More information about the Python-checkins mailing list