peps/pep-0279/index.html

304 lines
20 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 279 The enumerate() built-in function | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0279/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 279 The enumerate() built-in function | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0279/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 279</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 279 The enumerate() built-in function</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Raymond Hettinger &lt;python&#32;&#97;t&#32;rcn.com&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">30-Jan-2002</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.3</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even"><p></p></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#bdfl-pronouncements">BDFL Pronouncements</a></li>
<li><a class="reference internal" href="#specification-for-a-new-built-in">Specification for a new built-in</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>This PEP introduces a new built-in function, <code class="docutils literal notranslate"><span class="pre">enumerate()</span></code> to
simplify a commonly used looping idiom. It provides all iterable
collections with the same advantage that <code class="docutils literal notranslate"><span class="pre">iteritems()</span></code> affords to
dictionaries a compact, readable, reliable index notation.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>Python 2.2 introduced the concept of an iterable interface as
proposed in <a class="pep reference internal" href="../pep-0234/" title="PEP 234 Iterators">PEP 234</a>. The <code class="docutils literal notranslate"><span class="pre">iter()</span></code> factory function was provided
as common calling convention and deep changes were made to use
iterators as a unifying theme throughout Python. The unification
came in the form of establishing a common iterable interface for
mappings, sequences, and file objects.</p>
<p>Generators, as proposed in <a class="pep reference internal" href="../pep-0255/" title="PEP 255 Simple Generators">PEP 255</a>, were introduced as a means
for making it easier to create iterators, especially ones with
complex internal execution or variable states. The availability
of generators makes it possible to improve on the loop counter
ideas in <a class="pep reference internal" href="../pep-0212/" title="PEP 212 Loop Counter Iteration">PEP 212</a>. Those ideas provided a clean syntax for
iteration with indices and values, but did not apply to all
iterable objects. Also, that approach did not have the memory
friendly benefit provided by generators which do not evaluate the
entire sequence all at once.</p>
<p>The new proposal is to add a built-in function, <code class="docutils literal notranslate"><span class="pre">enumerate()</span></code> which
was made possible once iterators and generators became available.
It provides all iterables with the same advantage that <code class="docutils literal notranslate"><span class="pre">iteritems()</span></code>
affords to dictionaries a compact, readable, reliable index
notation. Like <code class="docutils literal notranslate"><span class="pre">zip()</span></code>, it is expected to become a commonly used
looping idiom.</p>
<p>This suggestion is designed to take advantage of the existing
implementation and require little additional effort to
incorporate. It is backwards compatible and requires no new
keywords. The proposal will go into Python 2.3 when generators
become final and are not imported from <code class="docutils literal notranslate"><span class="pre">__future__</span></code>.</p>
</section>
<section id="bdfl-pronouncements">
<h2><a class="toc-backref" href="#bdfl-pronouncements" role="doc-backlink">BDFL Pronouncements</a></h2>
<p>The new built-in function is ACCEPTED.</p>
</section>
<section id="specification-for-a-new-built-in">
<h2><a class="toc-backref" href="#specification-for-a-new-built-in" role="doc-backlink">Specification for a new built-in</a></h2>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">collection</span><span class="p">):</span>
<span class="s1">&#39;Generates an indexed series: (0,coll[0]), (1,coll[1]) ...&#39;</span>
<span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">it</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">collection</span><span class="p">)</span>
<span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">yield</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">it</span><span class="o">.</span><span class="n">next</span><span class="p">())</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>
</pre></div>
</div>
<p>Note A: <a class="pep reference internal" href="../pep-0212/" title="PEP 212 Loop Counter Iteration">PEP 212</a> Loop Counter Iteration discussed several
proposals for achieving indexing. Some of the proposals only work
for lists unlike the above function which works for any generator,
xrange, sequence, or iterable object. Also, those proposals were
presented and evaluated in the world prior to Python 2.2 which did
not include generators. As a result, the non-generator version in
<a class="pep reference internal" href="../pep-0212/" title="PEP 212 Loop Counter Iteration">PEP 212</a> had the disadvantage of consuming memory with a giant list
of tuples. The generator version presented here is fast and
light, works with all iterables, and allows users to abandon the
sequence in mid-stream with no loss of computation effort.</p>
<p>There are other PEPs which touch on related issues: integer
iterators, integer for-loops, and one for modifying the arguments
to <code class="docutils literal notranslate"><span class="pre">range</span></code> and <code class="docutils literal notranslate"><span class="pre">xrange</span></code>. The <code class="docutils literal notranslate"><span class="pre">enumerate()</span></code> proposal does not preclude
the other proposals and it still meets an important need even if
those are adopted the need to count items in any iterable. The
other proposals give a means of producing an index but not the
corresponding value. This is especially problematic if a sequence
is given which doesnt support random access such as a file
object, generator, or sequence defined with <code class="docutils literal notranslate"><span class="pre">__getitem__</span></code>.</p>
<p>Note B: Almost all of the PEP reviewers welcomed the function but
were divided as to whether there should be any built-ins. The
main argument for a separate module was to slow the rate of
language inflation. The main argument for a built-in was that the
function is destined to be part of a core programming style,
applicable to any object with an iterable interface. Just as
<code class="docutils literal notranslate"><span class="pre">zip()</span></code> solves the problem of looping over multiple sequences, the
<code class="docutils literal notranslate"><span class="pre">enumerate()</span></code> function solves the loop counter problem.</p>
<p>If only one built-in is allowed, then <code class="docutils literal notranslate"><span class="pre">enumerate()</span></code> is the most
important general purpose tool, solving the broadest class of
problems while improving program brevity, clarity and reliability.</p>
<p>Note C: Various alternative names were discussed:</p>
<table class="docutils align-default">
<tbody>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">iterindexed()</span></code></td>
<td>five syllables is a mouthful</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">index()</span></code></td>
<td>nice verb but could be confused the <code class="docutils literal notranslate"><span class="pre">.index()</span></code> method</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">indexed()</span></code></td>
<td>widely liked however adjectives should be avoided</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">indexer()</span></code></td>
<td>noun did not read well in a for-loop</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">count()</span></code></td>
<td>direct and explicit but often used in other contexts</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">itercount()</span></code></td>
<td>direct, explicit and hated by more than one person</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">iteritems()</span></code></td>
<td>conflicts with key:value concept for dictionaries</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">itemize()</span></code></td>
<td>confusing because <code class="docutils literal notranslate"><span class="pre">amap.items()</span></code> != <code class="docutils literal notranslate"><span class="pre">list(itemize(amap))</span></code></td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">enum()</span></code></td>
<td>pithy; less clear than enumerate; too similar to enum
in other languages where it has a different meaning</td>
</tr>
</tbody>
</table>
<p>All of the names involving count had the further disadvantage of
implying that the count would begin from one instead of zero.</p>
<p>All of the names involving index clashed with usage in database
languages where indexing implies a sorting operation rather than
linear sequencing.</p>
<p>Note D: This function was originally proposed with optional start
and stop arguments. GvR pointed out that the function call
<code class="docutils literal notranslate"><span class="pre">enumerate(seqn,4,6)</span></code> had an alternate, plausible interpretation as
a slice that would return the fourth and fifth elements of the
sequence. To avoid the ambiguity, the optional arguments were
dropped even though it meant losing flexibility as a loop counter.
That flexibility was most important for the common case of
counting from one, as in:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">linenum</span><span class="p">,</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">source</span><span class="p">,</span><span class="mi">1</span><span class="p">):</span> <span class="nb">print</span> <span class="n">linenum</span><span class="p">,</span> <span class="n">line</span>
</pre></div>
</div>
<dl>
<dt>Comments from GvR:</dt><dd><code class="docutils literal notranslate"><span class="pre">filter</span></code> and <code class="docutils literal notranslate"><span class="pre">map</span></code> should die and be subsumed into list
comprehensions, not grow more variants. Id rather introduce
built-ins that do iterator algebra (e.g. the iterzip that Ive
often used as an example).<p>I like the idea of having some way to iterate over a sequence
and its index set in parallel. Its fine for this to be a
built-in.</p>
<p>I dont like the name “indexed”; adjectives do not make good
function names. Maybe <code class="docutils literal notranslate"><span class="pre">iterindexed()</span></code>?</p>
</dd>
<dt>Comments from Ka-Ping Yee:</dt><dd>Im also quite happy with everything you
proposed … and the extra built-ins (really indexed in
particular) are things I have wanted for a long time.</dd>
<dt>Comments from Neil Schemenauer:</dt><dd>The new built-ins sound okay. Guido
may be concerned with increasing the number of built-ins too
much. You might be better off selling them as part of a
module. If you use a module then you can add lots of useful
functions (Haskell has lots of them that we could steal).</dd>
<dt>Comments for Magnus Lie Hetland:</dt><dd>I think indexed would be a useful and
natural built-in function. I would certainly use it a lot. I
like <code class="docutils literal notranslate"><span class="pre">indexed()</span></code> a lot; +1. Im quite happy to have it make PEP
281 obsolete. Adding a separate module for iterator utilities
seems like a good idea.</dd>
<dt>Comments from the Community:</dt><dd>The response to the <code class="docutils literal notranslate"><span class="pre">enumerate()</span></code> proposal
has been close to 100% favorable. Almost everyone loves the
idea.</dd>
<dt>Author response:</dt><dd>Prior to these comments, four built-ins were proposed.
After the comments, <code class="docutils literal notranslate"><span class="pre">xmap</span></code>, <code class="docutils literal notranslate"><span class="pre">xfilter</span></code> and <code class="docutils literal notranslate"><span class="pre">xzip</span></code> were withdrawn. The
one that remains is vital for the language and is proposed by
itself. <code class="docutils literal notranslate"><span class="pre">Indexed()</span></code> is trivially easy to implement and can be
documented in minutes. More importantly, it is useful in
everyday programming which does not otherwise involve explicit
use of generators.<p>This proposal originally included another function <code class="docutils literal notranslate"><span class="pre">iterzip()</span></code>.
That was subsequently implemented as the <code class="docutils literal notranslate"><span class="pre">izip()</span></code> function in
the <code class="docutils literal notranslate"><span class="pre">itertools</span></code> module.</p>
</dd>
</dl>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0279.rst">https://github.com/python/peps/blob/main/peps/pep-0279.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0279.rst">2023-09-09 17:39:29 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#bdfl-pronouncements">BDFL Pronouncements</a></li>
<li><a class="reference internal" href="#specification-for-a-new-built-in">Specification for a new built-in</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0279.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>