CINXE.COM
PEP 234 – Iterators | peps.python.org
<!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 234 – Iterators | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0234/"> <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 234 – Iterators | peps.python.org'> <meta property="og:description" content="This document proposes an iteration interface that objects can provide to control the behaviour of for loops. Looping is customized by providing a method that produces an iterator object. The iterator provides a get next value operation that produces ..."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0234/"> <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="This document proposes an iteration interface that objects can provide to control the behaviour of for loops. Looping is customized by providing a method that produces an iterator object. The iterator provides a get next value operation that produces ..."> <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> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 234</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 234 – Iterators</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Ka-Ping Yee <ping at zesty.ca>, Guido van Rossum <guido at python.org></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-2001</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">2.1</dd> <dt class="field-even">Post-History<span class="colon">:</span></dt> <dd class="field-even">30-Apr-2001</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="#c-api-specification">C API Specification</a></li> <li><a class="reference internal" href="#python-api-specification">Python API Specification</a></li> <li><a class="reference internal" href="#dictionary-iterators">Dictionary Iterators</a></li> <li><a class="reference internal" href="#file-iterators">File Iterators</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#resolved-issues">Resolved Issues</a></li> <li><a class="reference internal" href="#mailing-lists">Mailing Lists</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 document proposes an iteration interface that objects can provide to control the behaviour of <code class="docutils literal notranslate"><span class="pre">for</span></code> loops. Looping is customized by providing a method that produces an iterator object. The iterator provides a <em>get next value</em> operation that produces the next item in the sequence each time it is called, raising an exception when no more items are available.</p> <p>In addition, specific iterators over the keys of a dictionary and over the lines of a file are proposed, and a proposal is made to allow spelling <code class="docutils literal notranslate"><span class="pre">dict.has_key(key)</span></code> as <code class="docutils literal notranslate"><span class="pre">key</span> <span class="pre">in</span> <span class="pre">dict</span></code>.</p> <p>Note: this is an almost complete rewrite of this PEP by the second author, describing the actual implementation checked into the trunk of the Python 2.2 CVS tree. It is still open for discussion. Some of the more esoteric proposals in the original version of this PEP have been withdrawn for now; these may be the subject of a separate PEP in the future.</p> </section> <section id="c-api-specification"> <h2><a class="toc-backref" href="#c-api-specification" role="doc-backlink">C API Specification</a></h2> <p>A new exception is defined, <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code>, which can be used to signal the end of an iteration.</p> <p>A new slot named <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> for requesting an iterator is added to the type object structure. This should be a function of one <code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*</span></code> argument returning a <code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*</span></code>, or <code class="docutils literal notranslate"><span class="pre">NULL</span></code>. To use this slot, a new C API function <code class="docutils literal notranslate"><span class="pre">PyObject_GetIter()</span></code> is added, with the same signature as the <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> slot function.</p> <p>Another new slot, named <code class="docutils literal notranslate"><span class="pre">tp_iternext</span></code>, is added to the type structure, for obtaining the next value in the iteration. To use this slot, a new C API function <code class="docutils literal notranslate"><span class="pre">PyIter_Next()</span></code> is added. The signature for both the slot and the API function is as follows, although the <code class="docutils literal notranslate"><span class="pre">NULL</span></code> return conditions differ: the argument is a <code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*</span></code> and so is the return value. When the return value is non-<code class="docutils literal notranslate"><span class="pre">NULL</span></code>, it is the next value in the iteration. When it is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, then for the <code class="docutils literal notranslate"><span class="pre">tp_iternext</span> <span class="pre">slot</span></code> there are three possibilities:</p> <ul class="simple"> <li>No exception is set; this implies the end of the iteration.</li> <li>The <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> exception (or a derived exception class) is set; this implies the end of the iteration.</li> <li>Some other exception is set; this means that an error occurred that should be propagated normally.</li> </ul> <p>The higher-level <code class="docutils literal notranslate"><span class="pre">PyIter_Next()</span></code> function clears the <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> exception (or derived exception) when it occurs, so its <code class="docutils literal notranslate"><span class="pre">NULL</span></code> return conditions are simpler:</p> <ul class="simple"> <li>No exception is set; this means iteration has ended.</li> <li>Some exception is set; this means an error occurred, and should be propagated normally.</li> </ul> <p>Iterators implemented in C should <em>not</em> implement a <code class="docutils literal notranslate"><span class="pre">next()</span></code> method with similar semantics as the <code class="docutils literal notranslate"><span class="pre">tp_iternext</span></code> slot! When the type’s dictionary is initialized (by <code class="docutils literal notranslate"><span class="pre">PyType_Ready()</span></code>), the presence of a <code class="docutils literal notranslate"><span class="pre">tp_iternext</span></code> slot causes a method <code class="docutils literal notranslate"><span class="pre">next()</span></code> wrapping that slot to be added to the type’s <code class="docutils literal notranslate"><span class="pre">tp_dict</span></code>. (Exception: if the type doesn’t use <code class="docutils literal notranslate"><span class="pre">PyObject_GenericGetAttr()</span></code> to access instance attributes, the <code class="docutils literal notranslate"><span class="pre">next()</span></code> method in the type’s <code class="docutils literal notranslate"><span class="pre">tp_dict</span></code> may not be seen.) (Due to a misunderstanding in the original text of this PEP, in Python 2.2, all iterator types implemented a <code class="docutils literal notranslate"><span class="pre">next()</span></code> method that was overridden by the wrapper; this has been fixed in Python 2.3.)</p> <p>To ensure binary backwards compatibility, a new flag <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_ITER</span></code> is added to the set of flags in the <code class="docutils literal notranslate"><span class="pre">tp_flags</span></code> field, and to the default flags macro. This flag must be tested before accessing the <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> or <code class="docutils literal notranslate"><span class="pre">tp_iternext</span></code> slots. The macro <code class="docutils literal notranslate"><span class="pre">PyIter_Check()</span></code> tests whether an object has the appropriate flag set and has a non-<code class="docutils literal notranslate"><span class="pre">NULL</span></code> <code class="docutils literal notranslate"><span class="pre">tp_iternext</span></code> slot. There is no such macro for the <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> slot (since the only place where this slot is referenced should be <code class="docutils literal notranslate"><span class="pre">PyObject_GetIter()</span></code>, and this can check for the <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_ITER</span></code> flag directly).</p> <p>(Note: the <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> slot can be present on any object; the <code class="docutils literal notranslate"><span class="pre">tp_iternext</span></code> slot should only be present on objects that act as iterators.)</p> <p>For backwards compatibility, the <code class="docutils literal notranslate"><span class="pre">PyObject_GetIter()</span></code> function implements fallback semantics when its argument is a sequence that does not implement a <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> function: a lightweight sequence iterator object is constructed in that case which iterates over the items of the sequence in the natural order.</p> <p>The Python bytecode generated for <code class="docutils literal notranslate"><span class="pre">for</span></code> loops is changed to use new opcodes, <code class="docutils literal notranslate"><span class="pre">GET_ITER</span></code> and <code class="docutils literal notranslate"><span class="pre">FOR_ITER</span></code>, that use the iterator protocol rather than the sequence protocol to get the next value for the loop variable. This makes it possible to use a <code class="docutils literal notranslate"><span class="pre">for</span></code> loop to loop over non-sequence objects that support the <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> slot. Other places where the interpreter loops over the values of a sequence should also be changed to use iterators.</p> <p>Iterators ought to implement the <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> slot as returning a reference to themselves; this is needed to make it possible to use an iterator (as opposed to a sequence) in a <code class="docutils literal notranslate"><span class="pre">for</span></code> loop.</p> <p>Iterator implementations (in C or in Python) should guarantee that once the iterator has signalled its exhaustion, subsequent calls to <code class="docutils literal notranslate"><span class="pre">tp_iternext</span></code> or to the <code class="docutils literal notranslate"><span class="pre">next()</span></code> method will continue to do so. It is not specified whether an iterator should enter the exhausted state when an exception (other than <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code>) is raised. Note that Python cannot guarantee that user-defined or 3rd party iterators implement this requirement correctly.</p> </section> <section id="python-api-specification"> <h2><a class="toc-backref" href="#python-api-specification" role="doc-backlink">Python API Specification</a></h2> <p>The <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> exception is made visible as one of the standard exceptions. It is derived from <code class="docutils literal notranslate"><span class="pre">Exception</span></code>.</p> <p>A new built-in function is defined, <code class="docutils literal notranslate"><span class="pre">iter()</span></code>, which can be called in two ways:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">iter(obj)</span></code> calls <code class="docutils literal notranslate"><span class="pre">PyObject_GetIter(obj)</span></code>.</li> <li><code class="docutils literal notranslate"><span class="pre">iter(callable,</span> <span class="pre">sentinel)</span></code> returns a special kind of iterator that calls the callable to produce a new value, and compares the return value to the sentinel value. If the return value equals the sentinel, this signals the end of the iteration and <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> is raised rather than returning normal; if the return value does not equal the sentinel, it is returned as the next value from the iterator. If the callable raises an exception, this is propagated normally; in particular, the function is allowed to raise <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> as an alternative way to end the iteration. (This functionality is available from the C API as <code class="docutils literal notranslate"><span class="pre">PyCallIter_New(callable,</span> <span class="pre">sentinel)</span></code>.)</li> </ul> <p>Iterator objects returned by either form of <code class="docutils literal notranslate"><span class="pre">iter()</span></code> have a <code class="docutils literal notranslate"><span class="pre">next()</span></code> method. This method either returns the next value in the iteration, or raises <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> (or a derived exception class) to signal the end of the iteration. Any other exception should be considered to signify an error and should be propagated normally, not taken to mean the end of the iteration.</p> <p>Classes can define how they are iterated over by defining an <code class="docutils literal notranslate"><span class="pre">__iter__()</span></code> method; this should take no additional arguments and return a valid iterator object. A class that wants to be an iterator should implement two methods: a <code class="docutils literal notranslate"><span class="pre">next()</span></code> method that behaves as described above, and an <code class="docutils literal notranslate"><span class="pre">__iter__()</span></code> method that returns <code class="docutils literal notranslate"><span class="pre">self</span></code>.</p> <p>The two methods correspond to two distinct protocols:</p> <ol class="arabic simple"> <li>An object can be iterated over with <code class="docutils literal notranslate"><span class="pre">for</span></code> if it implements <code class="docutils literal notranslate"><span class="pre">__iter__()</span></code> or <code class="docutils literal notranslate"><span class="pre">__getitem__()</span></code>.</li> <li>An object can function as an iterator if it implements <code class="docutils literal notranslate"><span class="pre">next()</span></code>.</li> </ol> <p>Container-like objects usually support protocol 1. Iterators are currently required to support both protocols. The semantics of iteration come only from protocol 2; protocol 1 is present to make iterators behave like sequences; in particular so that code receiving an iterator can use a for-loop over the iterator.</p> </section> <section id="dictionary-iterators"> <h2><a class="toc-backref" href="#dictionary-iterators" role="doc-backlink">Dictionary Iterators</a></h2> <ul> <li>Dictionaries implement a <code class="docutils literal notranslate"><span class="pre">sq_contains</span></code> slot that implements the same test as the <code class="docutils literal notranslate"><span class="pre">has_key()</span></code> method. This means that we can write<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">dict</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> <p>which is equivalent to</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="nb">dict</span><span class="o">.</span><span class="n">has_key</span><span class="p">(</span><span class="n">k</span><span class="p">):</span> <span class="o">...</span> </pre></div> </div> </li> <li>Dictionaries implement a <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> slot that returns an efficient iterator that iterates over the keys of the dictionary. During such an iteration, the dictionary should not be modified, except that setting the value for an existing key is allowed (deletions or additions are not, nor is the <code class="docutils literal notranslate"><span class="pre">update()</span></code> method). This means that we can write<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">dict</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> <p>which is equivalent to, but much faster than</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">dict</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span> <span class="o">...</span> </pre></div> </div> <p>as long as the restriction on modifications to the dictionary (either by the loop or by another thread) are not violated.</p> </li> <li>Add methods to dictionaries that return different kinds of iterators explicitly:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="nb">dict</span><span class="o">.</span><span class="n">iterkeys</span><span class="p">():</span> <span class="o">...</span> <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">dict</span><span class="o">.</span><span class="n">itervalues</span><span class="p">():</span> <span class="o">...</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">dict</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span> <span class="o">...</span> </pre></div> </div> <p>This means that <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict</span></code> is shorthand for <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict.iterkeys()</span></code>.</p> </li> </ul> <p>Other mappings, if they support iterators at all, should also iterate over the keys. However, this should not be taken as an absolute rule; specific applications may have different requirements.</p> </section> <section id="file-iterators"> <h2><a class="toc-backref" href="#file-iterators" role="doc-backlink">File Iterators</a></h2> <p>The following proposal is useful because it provides us with a good answer to the complaint that the common idiom to iterate over the lines of a file is ugly and slow.</p> <ul> <li>Files implement a <code class="docutils literal notranslate"><span class="pre">tp_iter</span></code> slot that is equivalent to <code class="docutils literal notranslate"><span class="pre">iter(f.readline,</span> <span class="pre">"")</span></code>. This means that we can write<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">file</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> <p>as a shorthand for</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">iter</span><span class="p">(</span><span class="n">file</span><span class="o">.</span><span class="n">readline</span><span class="p">,</span> <span class="s2">""</span><span class="p">):</span> <span class="o">...</span> </pre></div> </div> <p>which is equivalent to, but faster than</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">while</span> <span class="mi">1</span><span class="p">:</span> <span class="n">line</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">line</span><span class="p">:</span> <span class="k">break</span> <span class="o">...</span> </pre></div> </div> </li> </ul> <p>This also shows that some iterators are destructive: they consume all the values and a second iterator cannot easily be created that iterates independently over the same values. You could open the file for a second time, or <code class="docutils literal notranslate"><span class="pre">seek()</span></code> to the beginning, but these solutions don’t work for all file types, e.g. they don’t work when the open file object really represents a pipe or a stream socket.</p> <p>Because the file iterator uses an internal buffer, mixing this with other file operations (e.g. <code class="docutils literal notranslate"><span class="pre">file.readline()</span></code>) doesn’t work right. Also, the following code:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">file</span><span class="p">:</span> <span class="k">if</span> <span class="n">line</span> <span class="o">==</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">:</span> <span class="k">break</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">file</span><span class="p">:</span> <span class="nb">print</span> <span class="n">line</span><span class="p">,</span> </pre></div> </div> <p>doesn’t work as you might expect, because the iterator created by the second for-loop doesn’t take the buffer read-ahead by the first for-loop into account. A correct way to write this is:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">it</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">file</span><span class="p">)</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">it</span><span class="p">:</span> <span class="k">if</span> <span class="n">line</span> <span class="o">==</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">:</span> <span class="k">break</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">it</span><span class="p">:</span> <span class="nb">print</span> <span class="n">line</span><span class="p">,</span> </pre></div> </div> <p>(The rationale for these restrictions are that <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">line</span> <span class="pre">in</span> <span class="pre">file</span></code> ought to become the recommended, standard way to iterate over the lines of a file, and this should be as fast as can be. The iterator version is considerable faster than calling <code class="docutils literal notranslate"><span class="pre">readline()</span></code>, due to the internal buffer in the iterator.)</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>If all the parts of the proposal are included, this addresses many concerns in a consistent and flexible fashion. Among its chief virtues are the following four – no, five – no, six – points:</p> <ol class="arabic simple"> <li>It provides an extensible iterator interface.</li> <li>It allows performance enhancements to list iteration.</li> <li>It allows big performance enhancements to dictionary iteration.</li> <li>It allows one to provide an interface for just iteration without pretending to provide random access to elements.</li> <li>It is backward-compatible with all existing user-defined classes and extension objects that emulate sequences and mappings, even mappings that only implement a subset of {<code class="docutils literal notranslate"><span class="pre">__getitem__</span></code>, <code class="docutils literal notranslate"><span class="pre">keys</span></code>, <code class="docutils literal notranslate"><span class="pre">values</span></code>, <code class="docutils literal notranslate"><span class="pre">items</span></code>}.</li> <li>It makes code iterating over non-sequence collections more concise and readable.</li> </ol> </section> <section id="resolved-issues"> <h2><a class="toc-backref" href="#resolved-issues" role="doc-backlink">Resolved Issues</a></h2> <p>The following topics have been decided by consensus or BDFL pronouncement.</p> <ul> <li>Two alternative spellings for <code class="docutils literal notranslate"><span class="pre">next()</span></code> have been proposed but rejected: <code class="docutils literal notranslate"><span class="pre">__next__()</span></code>, because it corresponds to a type object slot (<code class="docutils literal notranslate"><span class="pre">tp_iternext</span></code>); and <code class="docutils literal notranslate"><span class="pre">__call__()</span></code>, because this is the only operation.<p>Arguments against <code class="docutils literal notranslate"><span class="pre">__next__()</span></code>: while many iterators are used in for loops, it is expected that user code will also call <code class="docutils literal notranslate"><span class="pre">next()</span></code> directly, so having to write <code class="docutils literal notranslate"><span class="pre">__next__()</span></code> is ugly; also, a possible extension of the protocol would be to allow for <code class="docutils literal notranslate"><span class="pre">prev()</span></code>, <code class="docutils literal notranslate"><span class="pre">current()</span></code> and <code class="docutils literal notranslate"><span class="pre">reset()</span></code> operations; surely we don’t want to use <code class="docutils literal notranslate"><span class="pre">__prev__()</span></code>, <code class="docutils literal notranslate"><span class="pre">__current__()</span></code>, <code class="docutils literal notranslate"><span class="pre">__reset__()</span></code>.</p> <p>Arguments against <code class="docutils literal notranslate"><span class="pre">__call__()</span></code> (the original proposal): taken out of context, <code class="docutils literal notranslate"><span class="pre">x()</span></code> is not very readable, while <code class="docutils literal notranslate"><span class="pre">x.next()</span></code> is clear; there’s a danger that every special-purpose object wants to use <code class="docutils literal notranslate"><span class="pre">__call__()</span></code> for its most common operation, causing more confusion than clarity.</p> <p>(In retrospect, it might have been better to go for <code class="docutils literal notranslate"><span class="pre">__next__()</span></code> and have a new built-in, <code class="docutils literal notranslate"><span class="pre">next(it)</span></code>, which calls <code class="docutils literal notranslate"><span class="pre">it.__next__()</span></code>. But alas, it’s too late; this has been deployed in Python 2.2 since December 2001.)</p> </li> <li>Some folks have requested the ability to restart an iterator. This should be dealt with by calling <code class="docutils literal notranslate"><span class="pre">iter()</span></code> on a sequence repeatedly, not by the iterator protocol itself. (See also requested extensions below.)</li> <li>It has been questioned whether an exception to signal the end of the iteration isn’t too expensive. Several alternatives for the <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> exception have been proposed: a special value <code class="docutils literal notranslate"><span class="pre">End</span></code> to signal the end, a function <code class="docutils literal notranslate"><span class="pre">end()</span></code> to test whether the iterator is finished, even reusing the <code class="docutils literal notranslate"><span class="pre">IndexError</span></code> exception.<ul class="simple"> <li>A special value has the problem that if a sequence ever contains that special value, a loop over that sequence will end prematurely without any warning. If the experience with null-terminated C strings hasn’t taught us the problems this can cause, imagine the trouble a Python introspection tool would have iterating over a list of all built-in names, assuming that the special <code class="docutils literal notranslate"><span class="pre">End</span></code> value was a built-in name!</li> <li>Calling an <code class="docutils literal notranslate"><span class="pre">end()</span></code> function would require two calls per iteration. Two calls is much more expensive than one call plus a test for an exception. Especially the time-critical for loop can test very cheaply for an exception.</li> <li>Reusing <code class="docutils literal notranslate"><span class="pre">IndexError</span></code> can cause confusion because it can be a genuine error, which would be masked by ending the loop prematurely.</li> </ul> </li> <li>Some have asked for a standard iterator type. Presumably all iterators would have to be derived from this type. But this is not the Python way: dictionaries are mappings because they support <code class="docutils literal notranslate"><span class="pre">__getitem__()</span></code> and a handful other operations, not because they are derived from an abstract mapping type.</li> <li>Regarding <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">key</span> <span class="pre">in</span> <span class="pre">dict</span></code>: there is no doubt that the <code class="docutils literal notranslate"><span class="pre">dict.has_key(x)</span></code> interpretation of <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict</span></code> is by far the most useful interpretation, probably the only useful one. There has been resistance against this because <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">in</span> <span class="pre">list</span></code> checks whether <em>x</em> is present among the values, while the proposal makes <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict</span></code> check whether <em>x</em> is present among the keys. Given that the symmetry between lists and dictionaries is very weak, this argument does not have much weight.</li> <li>The name <code class="docutils literal notranslate"><span class="pre">iter()</span></code> is an abbreviation. Alternatives proposed include <code class="docutils literal notranslate"><span class="pre">iterate()</span></code>, <code class="docutils literal notranslate"><span class="pre">traverse()</span></code>, but these appear too long. Python has a history of using abbrs for common builtins, e.g. <code class="docutils literal notranslate"><span class="pre">repr()</span></code>, <code class="docutils literal notranslate"><span class="pre">str()</span></code>, <code class="docutils literal notranslate"><span class="pre">len()</span></code>.<p>Resolution: <code class="docutils literal notranslate"><span class="pre">iter()</span></code> it is.</p> </li> <li>Using the same name for two different operations (getting an iterator from an object and making an iterator for a function with a sentinel value) is somewhat ugly. I haven’t seen a better name for the second operation though, and since they both return an iterator, it’s easy to remember.<p>Resolution: the builtin <code class="docutils literal notranslate"><span class="pre">iter()</span></code> takes an optional argument, which is the sentinel to look for.</p> </li> <li>Once a particular iterator object has raised <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code>, will it also raise <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> on all subsequent <code class="docutils literal notranslate"><span class="pre">next()</span></code> calls? Some say that it would be useful to require this, others say that it is useful to leave this open to individual iterators. Note that this may require an additional state bit for some iterator implementations (e.g. function-wrapping iterators).<p>Resolution: once <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> is raised, calling <code class="docutils literal notranslate"><span class="pre">it.next()</span></code> continues to raise <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code>.</p> <p>Note: this was in fact not implemented in Python 2.2; there are many cases where an iterator’s <code class="docutils literal notranslate"><span class="pre">next()</span></code> method can raise <code class="docutils literal notranslate"><span class="pre">StopIteration</span></code> on one call but not on the next. This has been remedied in Python 2.3.</p> </li> <li>It has been proposed that a file object should be its own iterator, with a <code class="docutils literal notranslate"><span class="pre">next()</span></code> method returning the next line. This has certain advantages, and makes it even clearer that this iterator is destructive. The disadvantage is that this would make it even more painful to implement the “sticky StopIteration” feature proposed in the previous bullet.<p>Resolution: tentatively rejected (though there are still people arguing for this).</p> </li> <li>Some folks have requested extensions of the iterator protocol, e.g. <code class="docutils literal notranslate"><span class="pre">prev()</span></code> to get the previous item, <code class="docutils literal notranslate"><span class="pre">current()</span></code> to get the current item again, <code class="docutils literal notranslate"><span class="pre">finished()</span></code> to test whether the iterator is finished, and maybe even others, like <code class="docutils literal notranslate"><span class="pre">rewind()</span></code>, <code class="docutils literal notranslate"><span class="pre">__len__()</span></code>, <code class="docutils literal notranslate"><span class="pre">position()</span></code>.<p>While some of these are useful, many of these cannot easily be implemented for all iterator types without adding arbitrary buffering, and sometimes they can’t be implemented at all (or not reasonably). E.g. anything to do with reversing directions can’t be done when iterating over a file or function. Maybe a separate PEP can be drafted to standardize the names for such operations when they are implementable.</p> <p>Resolution: rejected.</p> </li> <li>There has been a long discussion about whether<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">dict</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> <p>should assign <em>x</em> the successive keys, values, or items of the dictionary. The symmetry between <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">y</span></code> and <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">y</span></code> suggests that it should iterate over keys. This symmetry has been observed by many independently and has even been used to “explain” one using the other. This is because for sequences, <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">y</span></code> iterates over <em>y</em> comparing the iterated values to <em>x</em>. If we adopt both of the above proposals, this will also hold for dictionaries.</p> <p>The argument against making <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict</span></code> iterate over the keys comes mostly from a practicality point of view: scans of the standard library show that there are about as many uses of <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict.items()</span></code> as there are of <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict.keys()</span></code>, with the <code class="docutils literal notranslate"><span class="pre">items()</span></code> version having a small majority. Presumably many of the loops using <code class="docutils literal notranslate"><span class="pre">keys()</span></code> use the corresponding value anyway, by writing <code class="docutils literal notranslate"><span class="pre">dict[x]</span></code>, so (the argument goes) by making both the key and value available, we could support the largest number of cases. While this is true, I (Guido) find the correspondence between <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict</span></code> and <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict</span></code> too compelling to break, and there’s not much overhead in having to write <code class="docutils literal notranslate"><span class="pre">dict[x]</span></code> to explicitly get the value.</p> <p>For fast iteration over items, use <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">key,</span> <span class="pre">value</span> <span class="pre">in</span> <span class="pre">dict.iteritems()</span></code>. I’ve timed the difference between</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="nb">dict</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> </pre></div> </div> <p>and</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">dict</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span> <span class="k">pass</span> </pre></div> </div> <p>and found that the latter is only about 7% faster.</p> <p>Resolution: By BDFL pronouncement, <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">dict</span></code> iterates over the keys, and dictionaries have <code class="docutils literal notranslate"><span class="pre">iteritems()</span></code>, <code class="docutils literal notranslate"><span class="pre">iterkeys()</span></code>, and <code class="docutils literal notranslate"><span class="pre">itervalues()</span></code> to return the different flavors of dictionary iterators.</p> </li> </ul> </section> <section id="mailing-lists"> <h2><a class="toc-backref" href="#mailing-lists" role="doc-backlink">Mailing Lists</a></h2> <p>The iterator protocol has been discussed extensively in a mailing list on SourceForge:</p> <blockquote> <div><a class="reference external" href="http://lists.sourceforge.net/lists/listinfo/python-iterators">http://lists.sourceforge.net/lists/listinfo/python-iterators</a></div></blockquote> <p>Initially, some of the discussion was carried out at Yahoo; archives are still accessible:</p> <blockquote> <div><a class="reference external" href="http://groups.yahoo.com/group/python-iter">http://groups.yahoo.com/group/python-iter</a></div></blockquote> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is 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-0234.rst">https://github.com/python/peps/blob/main/peps/pep-0234.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0234.rst">2025-02-01 08:55:40 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="#c-api-specification">C API Specification</a></li> <li><a class="reference internal" href="#python-api-specification">Python API Specification</a></li> <li><a class="reference internal" href="#dictionary-iterators">Dictionary Iterators</a></li> <li><a class="reference internal" href="#file-iterators">File Iterators</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#resolved-issues">Resolved Issues</a></li> <li><a class="reference internal" href="#mailing-lists">Mailing Lists</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-0234.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>