PEP: 281
Title: Loop Counter Iteration with range and xrange
Version: $Revision: 2068 $
Last-Modified: $Date: 2005-06-17 11:28:49 -0700 (Fri, 17 Jun 2005) $
Author: Magnus Lie Hetland <magnus at>
Status: Rejected
Type: Standards Track
Created: 11-Feb-2002
Python-Version: 2.3


   This PEP describes yet another way of exposing the loop counter in
   for-loops. It basically proposes that the functionality of the
   function indices() from PEP 212 [1] be included in the existing
   functions range() and xrange().


   In commenting on PEP 279's enumerate() function, this PEP's author
   offered, "I'm quite happy to have it make PEP 281 obsolete."
   Subsequently, PEP 279 was accepted into Python 2.3.

   On 17 June 2005, the BDFL concurred with it being obsolete and
   hereby rejected the PEP.  For the record, he found some of the
   examples to somewhat jarring in appearance:

      >>> range(range(5), range(10), range(2))
      [5, 7, 9]


   It is often desirable to loop over the indices of a sequence.  PEP
   212 describes several ways of doing this, including adding a
   built-in function called indices, conceptually defined as

       def indices(sequence):
           return range(len(sequence))

   On the assumption that adding functionality to an existing built-in
   function may be less intrusive than adding a new built-in function,
   this PEP proposes adding this functionality to the existing
   functions range() and xrange().


   It is proposed that all three arguments to the built-in functions
   range() and xrange() are allowed to be objects with a length
   (i.e. objects implementing the __len__ method).  If an argument
   cannot be interpreted as an integer (i.e. it has no __int__
   method), its length will be used instead.


   >>> range(range(10))
   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
   >>> range(range(5), range(10))
   [5, 6, 7, 8, 9]
   >>> range(range(5), range(10), range(2))
   [5, 7, 9]
   >>> list(xrange(range(10)))
   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
   >>> list(xrange(xrange(10)))
   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

   # Number the lines of a file:
   lines = file.readlines()
   for num in range(lines):
       print num, lines[num]


   A natural alternative to the above specification is allowing
   xrange() to access its arguments in a lazy manner.  Thus, instead
   of using their length explicitly, xrange can return one index for
   each element of the stop argument until the end is reached.  A
   similar lazy treatment makes little sense for the start and step
   arguments since their length must be calculated before iteration
   can begin.  (Actually, the length of the step argument isn't needed
   until the second element is returned.)

   A pseudo-implementation (using only the stop argument, and assuming
   that it is iterable) is:

   def xrange(stop):
       i = 0
       for x in stop:
           yield i
           i += 1

   Testing whether to use int() or lazy iteration could be done by
   checking for an __iter__ attribute.  (This example assumes the
   presence of generators, but could easily have been implemented as a
   plain iterator object.)

   It may be questionable whether this feature is truly useful, since
   one would not be able to access the elements of the iterable object
   inside the for loop through indexing.


   # Printing the numbers of the lines of a file:
   for num in range(file):
       print num # The line itself is not accessible

   A more controversial alternative (to deal with this) would be to
   let range() behave like the function irange() of PEP 212 when
   supplied with a sequence.


   >>> range(5)
   [0, 1, 2, 3, 4]
   >>> range('abcde')
   [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')]

Backwards Compatibility

   The proposal could cause backwards incompatibilities if arguments
   are used which implement both __int__ and __len__ (or __iter__ in
   the case of lazy iteration with xrange).  The author does not
   believe that this is a significant problem.

References and Footnotes

   [1] PEP 212, Loop Counter Iteration


    This document has been placed in the public domain.