141 lines
4.1 KiB
Plaintext
141 lines
4.1 KiB
Plaintext
PEP: 281
|
|
Title: Loop Counter Iteration with range and xrange
|
|
Author: Magnus Lie Hetland <magnus@hetland.org>
|
|
Status: Rejected
|
|
Type: Standards Track
|
|
Content-Type: text/x-rst
|
|
Created: 11-Feb-2002
|
|
Python-Version: 2.3
|
|
Post-History:
|
|
|
|
|
|
Abstract
|
|
========
|
|
|
|
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` be included in the existing
|
|
functions ``range()`` and ``xrange()``.
|
|
|
|
|
|
Pronouncement
|
|
=============
|
|
|
|
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]
|
|
|
|
|
|
Motivation
|
|
==========
|
|
|
|
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()``.
|
|
|
|
|
|
Specification
|
|
=============
|
|
|
|
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.
|
|
|
|
Examples::
|
|
|
|
>>> 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]
|
|
|
|
|
|
Alternatives
|
|
============
|
|
|
|
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.
|
|
|
|
Example::
|
|
|
|
# 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.
|
|
|
|
Example::
|
|
|
|
>>> 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.
|
|
|
|
|
|
Copyright
|
|
=========
|
|
|
|
This document has been placed in the public domain.
|