PEP: 212
Title: Loop Counter Iteration
Version: $Revision: 651 $
Author: Peter Schneider-Kamp <nowonder at nowonder.de>
Status: Draft
Type: Standards Track
Created: 22-Aug-2000
Python-Version: 2.1

Introduction

    This PEP describes the often proposed feature of exposing the loop
    counter in for-loops.  This PEP tracks the status and ownership of
    this feature.  It contains a description of the feature and
    outlines changes necessary to support the feature.  This PEP
    summarizes discussions held in mailing list forums, and provides
    URLs for further information, where appropriate.  The CVS revision
    history of this file contains the definitive historical record.


Motivation

    Standard for-loops in Python iterate over the elements of a
    sequence[1].  Often it is desirable to loop over the indices or
    both the elements and the indices instead.

    The common idioms used to accomplish this are unintuitive.  This
    PEP proposes two different ways of exposing the indices.


Loop counter iteration

    The current idiom for looping over the indices makes use of the
    built-in 'range' function:

        for i in range(len(sequence)):
            # work with index i

    Looping over both elements and indices can be achieved either by the
    old idiom or by using the new 'zip' built-in function[2]:

        for i in range(len(sequence)):
            e = sequence[i]
            # work with index i and element e

    or

        for i, e in zip(range(len(sequence)), sequence):
            # work with index i and element e


The Proposed Solutions

    There are three solutions that have been discussed.  One adds a
    non-reserved keyword, the other adds two built-in functions.
    A third solution adds methods to sequence objects.


Non-reserved keyword 'indexing'

    This solution would extend the syntax of the for-loop by adding
    an optional '<variable> indexing' clause which can also be used
    instead of the '<variable> in' clause..

    Looping over the indices of a sequence would thus become:

        for i indexing sequence:
            # work with index i

    Looping over both indices and elements would similarly be:

        for i indexing e in sequence:
            # work with index i and element e


Built-in functions 'indices' and 'irange'

    This solution adds two built-in functions 'indices' and 'irange'.
    The semantics of these can be described as follows:

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

        def irange(sequence):
            return zip(range(len(sequence)), sequence)

    These functions could be implemented either eagerly or lazily and
    should be easy to extend in order to accept more than one sequence
    argument.

    The use of these functions would simplify the idioms for looping
    over the indices and over both elements and indices:

        for i in indices(sequence):
            # work with index i

        for i, e in irange(sequence):
            # work with index i and element e


Methods for sequence objects

    This solution proposes the addition of 'indices', 'items'
    and 'values' methods to sequences, which enable looping over
    indices only, both indices and elements, and elements only
    respectively.

    This would immensely simplify the idioms for looping over indices
    and for looping over both elements and indices:

        for i in sequence.indices():
            # work with index i

        for i, e in sequence.items():
            # work with index i and element e

    Additionally it would allow to do looping over the elements
    of sequences and dicitionaries in a consistent way:

        for e in sequence_or_dict.values():
            # do something with element e


Implementations

    For all three solutions some more or less rough patches exist
    as patches at SourceForge:

        'for i indexing a in l': exposing the for-loop counter[3]
        add indices() and irange() to built-ins[4]
        add items() method to listobject[5]

    All of them have been pronounced on and rejected by the BDFL.

    Note that the 'indexing' keyword is only a NAME in the
    grammar and so does not hinder the general use of 'indexing'.


Backward Compatibility Issues

    As no keywords are added and the semantics of existing code
    remains unchanged, all three solutions can be implemented
    without breaking existing code.


Copyright

    This document has been placed in the public domain.


References

    [1] http://www.python.org/doc/current/ref/for.html
    [2] Lockstep Iteration, pep-0201.txt
    [3] http://sourceforge.net/patch/download.php?id=101138
    [4] http://sourceforge.net/patch/download.php?id=101129
    [5] http://sourceforge.net/patch/download.php?id=101178