Permalink
Cannot retrieve contributors at this time
158 lines (115 sloc)
4.32 KB
| PEP: 281 | |
| Title: Loop Counter Iteration with range and xrange | |
| Version: $Revision$ | |
| Last-Modified: $Date$ | |
| Author: magnus@hetland.org (Magnus Lie Hetland) | |
| 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 [1]_ 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. | |
| References and Footnotes | |
| ======================== | |
| .. [1] PEP 212, Loop Counter Iteration | |
| http://www.python.org/dev/peps/pep-0212/ | |
| Copyright | |
| ========= | |
| This document has been placed in the public domain. | |
| .. | |
| Local Variables: | |
| mode: indented-text | |
| indent-tabs-mode: nil | |
| fill-column: 70 | |
| End: |