CINXE.COM
PEP 3142 – Add a “while” clause to generator expressions | 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 3142 – Add a “while” clause to generator expressions | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-3142/"> <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 3142 – Add a “while” clause to generator expressions | peps.python.org'> <meta property="og:description" content="This PEP proposes an enhancement to generator expressions, adding a “while” clause to complement the existing “if” clause."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-3142/"> <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 PEP proposes an enhancement to generator expressions, adding a “while” clause to complement the existing “if” clause."> <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 3142</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 3142 – Add a “while” clause to generator expressions</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Gerald Britton <gerald.britton at gmail.com></dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</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">12-Jan-2009</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">3.0</dd> <dt class="field-even">Post-History<span class="colon">:</span></dt> <dd class="field-even"><p></p></dd> <dt class="field-odd">Resolution<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2013-May/126136.html">Python-Dev message</a></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="#acknowledgements">Acknowledgements</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 proposes an enhancement to generator expressions, adding a “while” clause to complement the existing “if” clause.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>A generator expression (<a class="pep reference internal" href="../pep-0289/" title="PEP 289 – Generator Expressions">PEP 289</a>) is a concise method to serve dynamically-generated objects to list comprehensions (<a class="pep reference internal" href="../pep-0202/" title="PEP 202 – List Comprehensions">PEP 202</a>). Current generator expressions allow for an “if” clause to filter the objects that are returned to those meeting some set of criteria. However, since the “if” clause is evaluated for every object that may be returned, in some cases it is possible that all objects would be rejected after a certain point. For example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">g</span> <span class="o">=</span> <span class="p">(</span><span class="n">n</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span> <span class="k">if</span> <span class="n">n</span><span class="o">*</span><span class="n">n</span> <span class="o"><</span> <span class="mi">50</span><span class="p">)</span> </pre></div> </div> <p>which is equivalent to the using a generator function (<a class="pep reference internal" href="../pep-0255/" title="PEP 255 – Simple Generators">PEP 255</a>):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">__gen</span><span class="p">(</span><span class="n">exp</span><span class="p">):</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">exp</span><span class="p">:</span> <span class="k">if</span> <span class="n">n</span><span class="o">*</span><span class="n">n</span> <span class="o"><</span> <span class="mi">50</span><span class="p">:</span> <span class="k">yield</span> <span class="n">n</span> <span class="n">g</span> <span class="o">=</span> <span class="n">__gen</span><span class="p">(</span><span class="nb">iter</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)))</span> </pre></div> </div> <p>would yield 0, 1, 2, 3, 4, 5, 6 and 7, but would also consider the numbers from 8 to 99 and reject them all since <code class="docutils literal notranslate"><span class="pre">n*n</span> <span class="pre">>=</span> <span class="pre">50</span></code> for numbers in that range. Allowing for a “while” clause would allow the redundant tests to be short-circuited:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">g</span> <span class="o">=</span> <span class="p">(</span><span class="n">n</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span> <span class="k">while</span> <span class="n">n</span><span class="o">*</span><span class="n">n</span> <span class="o"><</span> <span class="mi">50</span><span class="p">)</span> </pre></div> </div> <p>would also yield 0, 1, 2, 3, 4, 5, 6 and 7, but would stop at 8 since the condition (<code class="docutils literal notranslate"><span class="pre">n*n</span> <span class="pre"><</span> <span class="pre">50</span></code>) is no longer true. This would be equivalent to the generator function:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">__gen</span><span class="p">(</span><span class="n">exp</span><span class="p">):</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">exp</span><span class="p">:</span> <span class="k">if</span> <span class="n">n</span><span class="o">*</span><span class="n">n</span> <span class="o"><</span> <span class="mi">50</span><span class="p">:</span> <span class="k">yield</span> <span class="n">n</span> <span class="k">else</span><span class="p">:</span> <span class="k">break</span> <span class="n">g</span> <span class="o">=</span> <span class="n">__gen</span><span class="p">(</span><span class="nb">iter</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">)))</span> </pre></div> </div> <p>Currently, in order to achieve the same result, one would need to either write a generator function such as the one above or use the takewhile function from itertools:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">itertools</span><span class="w"> </span><span class="kn">import</span> <span class="n">takewhile</span> <span class="n">g</span> <span class="o">=</span> <span class="n">takewhile</span><span class="p">(</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span><span class="o">*</span><span class="n">n</span> <span class="o"><</span> <span class="mi">50</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">))</span> </pre></div> </div> <p>The takewhile code achieves the same result as the proposed syntax, albeit in a longer (some would say “less-elegant”) fashion. Also, the takewhile version requires an extra function call (the lambda in the example above) with the associated performance penalty. A simple test shows that:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="p">(</span><span class="n">n</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span> <span class="k">if</span> <span class="mi">1</span><span class="p">):</span> <span class="k">pass</span> </pre></div> </div> <p>performs about 10% better than:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">takewhile</span><span class="p">(</span><span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">)):</span> <span class="k">pass</span> </pre></div> </div> <p>though they achieve similar results. (The first example uses a generator; takewhile is an iterator). If similarly implemented, a “while” clause should perform about the same as the “if” clause does today.</p> <p>The reader may ask if the “if” and “while” clauses should be mutually exclusive. There are good examples that show that there are times when both may be used to good advantage. For example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">p</span> <span class="o">=</span> <span class="p">(</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">primes</span><span class="p">()</span> <span class="k">if</span> <span class="n">p</span> <span class="o">></span> <span class="mi">100</span> <span class="k">while</span> <span class="n">p</span> <span class="o"><</span> <span class="mi">1000</span><span class="p">)</span> </pre></div> </div> <p>should return prime numbers found between 100 and 1000, assuming I have a <code class="docutils literal notranslate"><span class="pre">primes()</span></code> generator that yields prime numbers.</p> <p>Adding a “while” clause to generator expressions maintains the compact form while adding a useful facility for short-circuiting the expression.</p> </section> <section id="acknowledgements"> <h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2> <p>Raymond Hettinger first proposed the concept of generator expressions in January 2002.</p> </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-3142.rst">https://github.com/python/peps/blob/main/peps/pep-3142.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-3142.rst">2025-02-01 08:59:27 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="#acknowledgements">Acknowledgements</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-3142.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>