python-peps/pep-0284/index.html

372 lines
26 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 284 Integer for-loops | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0284/">
<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 284 Integer for-loops | peps.python.org'>
<meta property="og:description" content="This PEP proposes to simplify iteration over intervals of integers, by extending the range of expressions allowed after a “for” keyword to allow three-way comparisons such as">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0284/">
<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 to simplify iteration over intervals of integers, by extending the range of expressions allowed after a “for” keyword to allow three-way comparisons such as">
<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 284</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 284 Integer for-loops</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">David Eppstein &lt;eppstein&#32;&#97;t&#32;ics.uci.edu&gt;,
Gregory Ewing &lt;greg.ewing&#32;&#97;t&#32;canterbury.ac.nz&gt;</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">01-Mar-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="#pronouncement">Pronouncement</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#issues">Issues</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#references">References</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 to simplify iteration over intervals of
integers, by extending the range of expressions allowed after a
“for” keyword to allow three-way comparisons such as</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">lower</span> <span class="o">&lt;=</span> <span class="n">var</span> <span class="o">&lt;</span> <span class="n">upper</span><span class="p">:</span>
</pre></div>
</div>
<p>in place of the current</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">:</span>
</pre></div>
</div>
<p>syntax. The resulting loop or list iteration will loop over all
values of var that make the comparison true, starting from the
left endpoint of the given interval.</p>
</section>
<section id="pronouncement">
<h2><a class="toc-backref" href="#pronouncement" role="doc-backlink">Pronouncement</a></h2>
<p>This PEP is rejected. There were a number of fixable issues with
the proposal (see the fixups listed in Raymond Hettingers
python-dev post on 18 June 2005 <a class="footnote-reference brackets" href="#id2" id="id1">[1]</a>). However, even with the fixups the
proposal did not garner support. Specifically, Guido did not buy
the premise that the <code class="docutils literal notranslate"><span class="pre">range()</span></code> format needed fixing, “The whole point
(15 years ago) of <code class="docutils literal notranslate"><span class="pre">range()</span></code> was to <em>avoid</em> needing syntax to specify a
loop over numbers. I think its worked out well and theres nothing
that needs to be fixed (except <code class="docutils literal notranslate"><span class="pre">range()</span></code> needs to become an iterator,
which it will in Python 3.0).”</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>One of the most common uses of for-loops in Python is to iterate
over an interval of integers. Python provides functions <code class="docutils literal notranslate"><span class="pre">range()</span></code>
and <code class="docutils literal notranslate"><span class="pre">xrange()</span></code> to generate lists and iterators for such intervals,
which work best for the most frequent case: half-open intervals
increasing from zero. However, the <code class="docutils literal notranslate"><span class="pre">range()</span></code> syntax is more awkward
for open or closed intervals, and lacks symmetry when reversing
the order of iteration. In addition, the call to an unfamiliar
function makes it difficult for newcomers to Python to understand
code that uses <code class="docutils literal notranslate"><span class="pre">range()</span></code> or <code class="docutils literal notranslate"><span class="pre">xrange()</span></code>.</p>
<p>The perceived lack of a natural, intuitive integer iteration
syntax has led to heated debate on python-list, and spawned at
least four PEPs before this one. <a class="pep reference internal" href="../pep-0204/" title="PEP 204 Range Literals">PEP 204</a> (rejected) proposed
to re-use Pythons slice syntax for integer ranges, leading to a
terser syntax but not solving the readability problem of
multi-argument <code class="docutils literal notranslate"><span class="pre">range()</span></code>. <a class="pep reference internal" href="../pep-0212/" title="PEP 212 Loop Counter Iteration">PEP 212</a> (deferred) proposed several
syntaxes for directly converting a list to a sequence of integer
indices, in place of the current idiom</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nb">list</span><span class="p">))</span>
</pre></div>
</div>
<p>for such conversion, and <a class="pep reference internal" href="../pep-0281/" title="PEP 281 Loop Counter Iteration with range and xrange">PEP 281</a> proposes to simplify the same
idiom by allowing it to be written as</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">range</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span><span class="o">.</span>
</pre></div>
</div>
<p><a class="pep reference internal" href="../pep-0276/" title="PEP 276 Simple Iterator for ints">PEP 276</a> proposes to allow automatic conversion of integers to
iterators, simplifying the most common half-open case but not
addressing the complexities of other types of interval.
Additional alternatives have been discussed on python-list.</p>
<p>The solution described here is to allow a three-way comparison
after a “for” keyword, both in the context of a for-loop and of a
list comprehension:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">lower</span> <span class="o">&lt;=</span> <span class="n">var</span> <span class="o">&lt;</span> <span class="n">upper</span><span class="p">:</span>
</pre></div>
</div>
<p>This would cause iteration over an interval of consecutive
integers, beginning at the left bound in the comparison and ending
at the right bound. The exact comparison operations used would
determine whether the interval is open or closed at either end and
whether the integers are considered in ascending or descending
order.</p>
<p>This syntax closely matches standard mathematical notation, so is
likely to be more familiar to Python novices than the current
<code class="docutils literal notranslate"><span class="pre">range()</span></code> syntax. Open and closed interval endpoints are equally
easy to express, and the reversal of an integer interval can be
formed simply by swapping the two endpoints and reversing the
comparisons. In addition, the semantics of such a loop would
closely resemble one way of interpreting the existing Python
for-loops:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="nb">list</span>
</pre></div>
</div>
<p>iterates over exactly those values of item that cause the
expression</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">item</span> <span class="ow">in</span> <span class="nb">list</span>
</pre></div>
</div>
<p>to be true. Similarly, the new format</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">lower</span> <span class="o">&lt;=</span> <span class="n">var</span> <span class="o">&lt;</span> <span class="n">upper</span><span class="p">:</span>
</pre></div>
</div>
<p>would iterate over exactly those integer values of var that cause
the expression</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">lower</span> <span class="o">&lt;=</span> <span class="n">var</span> <span class="o">&lt;</span> <span class="n">upper</span>
</pre></div>
</div>
<p>to be true.</p>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>We propose to extend the syntax of a for statement, currently</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">for_stmt</span><span class="p">:</span> <span class="s2">&quot;for&quot;</span> <span class="n">target_list</span> <span class="s2">&quot;in&quot;</span> <span class="n">expression_list</span> <span class="s2">&quot;:&quot;</span> <span class="n">suite</span>
<span class="p">[</span><span class="s2">&quot;else&quot;</span> <span class="s2">&quot;:&quot;</span> <span class="n">suite</span><span class="p">]</span>
</pre></div>
</div>
<p>as described below:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">for_stmt</span><span class="p">:</span> <span class="s2">&quot;for&quot;</span> <span class="n">for_test</span> <span class="s2">&quot;:&quot;</span> <span class="n">suite</span> <span class="p">[</span><span class="s2">&quot;else&quot;</span> <span class="s2">&quot;:&quot;</span> <span class="n">suite</span><span class="p">]</span>
<span class="n">for_test</span><span class="p">:</span> <span class="n">target_list</span> <span class="s2">&quot;in&quot;</span> <span class="n">expression_list</span> <span class="o">|</span>
<span class="n">or_expr</span> <span class="n">less_comp</span> <span class="n">or_expr</span> <span class="n">less_comp</span> <span class="n">or_expr</span> <span class="o">|</span>
<span class="n">or_expr</span> <span class="n">greater_comp</span> <span class="n">or_expr</span> <span class="n">greater_comp</span> <span class="n">or_expr</span>
<span class="n">less_comp</span><span class="p">:</span> <span class="s2">&quot;&lt;&quot;</span> <span class="o">|</span> <span class="s2">&quot;&lt;=&quot;</span>
<span class="n">greater_comp</span><span class="p">:</span> <span class="s2">&quot;&gt;&quot;</span> <span class="o">|</span> <span class="s2">&quot;&gt;=&quot;</span>
</pre></div>
</div>
<p>Similarly, we propose to extend the syntax of list comprehensions,
currently</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">list_for</span><span class="p">:</span> <span class="s2">&quot;for&quot;</span> <span class="n">expression_list</span> <span class="s2">&quot;in&quot;</span> <span class="n">testlist</span> <span class="p">[</span><span class="n">list_iter</span><span class="p">]</span>
</pre></div>
</div>
<p>by replacing it with:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">list_for</span><span class="p">:</span> <span class="s2">&quot;for&quot;</span> <span class="n">for_test</span> <span class="p">[</span><span class="n">list_iter</span><span class="p">]</span>
</pre></div>
</div>
<p>In all cases the expression formed by for_test would be subject to
the same precedence rules as comparisons in expressions. The two
comp_operators in a for_test must be required to be both of
similar types, unlike chained comparisons in expressions which do
not have such a restriction.</p>
<p>We refer to the two or_exprs occurring on the left and right
sides of the for-loop syntax as the bounds of the loop, and the
middle or_expr as the variable of the loop. When a for-loop using
the new syntax is executed, the expressions for both bounds will
be evaluated, and an iterator object created that iterates through
all integers between the two bounds according to the comparison
operations used. The iterator will begin with an integer equal or
near to the left bound, and then step through the remaining
integers with a step size of +1 or -1 if the comparison operation
is in the set described by less_comp or greater_comp respectively.
The execution will then proceed as if the expression had been</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">variable</span> <span class="ow">in</span> <span class="n">iterator</span>
</pre></div>
</div>
<p>where “variable” refers to the variable of the loop and “iterator”
refers to the iterator created for the given integer interval.</p>
<p>The values taken by the loop variable in an integer for-loop may
be either plain integers or long integers, according to the
magnitude of the bounds. Both bounds of an integer for-loop must
evaluate to a real numeric type (integer, long, or float). Any
other value will cause the for-loop statement to raise a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>
exception.</p>
</section>
<section id="issues">
<h2><a class="toc-backref" href="#issues" role="doc-backlink">Issues</a></h2>
<p>The following issues were raised in discussion of this and related
proposals on the Python list.</p>
<ul>
<li>Should the right bound be evaluated once, or every time through
the loop? Clearly, it only makes sense to evaluate the left
bound once. For reasons of consistency and efficiency, we have
chosen the same convention for the right bound.</li>
<li>Although the new syntax considerably simplifies integer
for-loops, list comprehensions using the new syntax are not as
simple. We feel that this is appropriate since for-loops are
more frequent than comprehensions.</li>
<li>The proposal does not allow access to integer iterator objects
such as would be created by <code class="docutils literal notranslate"><span class="pre">xrange</span></code>. True, but we see this as a
shortcoming in the general list-comprehension syntax, beyond the
scope of this proposal. In addition, <code class="docutils literal notranslate"><span class="pre">xrange()</span></code> will still be
available.</li>
<li>The proposal does not allow increments other than 1 and -1.
More general arithmetic progressions would need to be created by
<code class="docutils literal notranslate"><span class="pre">range()</span></code> or <code class="docutils literal notranslate"><span class="pre">xrange()</span></code>, or by a list comprehension syntax such as<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="mi">2</span><span class="o">*</span><span class="n">x</span> <span class="k">for</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">x</span> <span class="o">&lt;=</span> <span class="mi">100</span><span class="p">]</span>
</pre></div>
</div>
</li>
<li>The position of the loop variable in the middle of a three-way
comparison is not as apparent as the variable in the present<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="nb">list</span>
</pre></div>
</div>
<p>syntax, leading to a possible loss of readability. We feel that
this loss is outweighed by the increase in readability from a
natural integer iteration syntax.</p>
</li>
<li>To some extent, this PEP addresses the same issues as <a class="pep reference internal" href="../pep-0276/" title="PEP 276 Simple Iterator for ints">PEP 276</a>.
We feel that the two PEPs are not in conflict since <a class="pep reference internal" href="../pep-0276/" title="PEP 276 Simple Iterator for ints">PEP 276</a>
is primarily concerned with half-open ranges starting in 0
(the easy case of <code class="docutils literal notranslate"><span class="pre">range()</span></code>) while this PEP is primarily concerned
with simplifying all other cases. However, if this PEP is
approved, its new simpler syntax for integer loops could to some
extent reduce the motivation for <a class="pep reference internal" href="../pep-0276/" title="PEP 276 Simple Iterator for ints">PEP 276</a>.</li>
<li>It is not clear whether it makes sense to allow floating point
bounds for an integer loop: if a float represents an inexact
value, how can it be used to determine an exact sequence of
integers? On the other hand, disallowing float bounds would
make it difficult to use <code class="docutils literal notranslate"><span class="pre">floor()</span></code> and <code class="docutils literal notranslate"><span class="pre">ceiling()</span></code> in integer
for-loops, as it is difficult to use them now with <code class="docutils literal notranslate"><span class="pre">range()</span></code>. We
have erred on the side of flexibility, but this may lead to some
implementation difficulties in determining the smallest and
largest integer values that would cause a given comparison to be
true.</li>
<li>Should types other than int, long, and float be allowed as
bounds? Another choice would be to convert all bounds to
integers by <code class="docutils literal notranslate"><span class="pre">int()</span></code>, and allow as bounds anything that can be so
converted instead of just floats. However, this would change
the semantics: <code class="docutils literal notranslate"><span class="pre">0.3</span> <span class="pre">&lt;=</span> <span class="pre">x</span></code> is not the same as <code class="docutils literal notranslate"><span class="pre">int(0.3)</span> <span class="pre">&lt;=</span> <span class="pre">x</span></code>, and it
would be confusing for a loop with 0.3 as lower bound to start
at zero. Also, in general <code class="docutils literal notranslate"><span class="pre">int(f)</span></code> can be very far from <code class="docutils literal notranslate"><span class="pre">f</span></code>.</li>
</ul>
</section>
<section id="implementation">
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
<p>An implementation is not available at this time. Implementation
is not expected to pose any great difficulties: the new syntax
could, if necessary, be recognized by parsing a general expression
after each “for” keyword and testing whether the top level
operation of the expression is “in” or a three-way comparison.
The Python compiler would convert any instance of the new syntax
into a loop over the items in a special iterator object.</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id2" role="doc-footnote">
<dt class="label" id="id2">[<a href="#id1">1</a>]</dt>
<dd>Raymond Hettinger, Propose updating PEP 284 Integer for-loops
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2005-June/054316.html">https://mail.python.org/pipermail/python-dev/2005-June/054316.html</a></aside>
</aside>
</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-0284.rst">https://github.com/python/peps/blob/main/peps/pep-0284.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0284.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="#pronouncement">Pronouncement</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#issues">Issues</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#references">References</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-0284.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>