mirror of https://github.com/python/peps
565 lines
42 KiB
HTML
565 lines
42 KiB
HTML
|
||
<!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 3136 – Labeled break and continue | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-3136/">
|
||
<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 3136 – Labeled break and continue | peps.python.org'>
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-3136/">
|
||
<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> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
||
<li>PEP 3136</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 3136 – Labeled break and continue</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Matt Chisholm <matt-python at theory.org></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">30-Jun-2007</dd>
|
||
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-odd">3.1</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="#rejection-notice">Rejection Notice</a></li>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#introduction">Introduction</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#other-languages">Other languages</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#what-this-pep-is-not">What this PEP is not</a></li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#proposal-a-explicit-labels">Proposal A - Explicit labels</a></li>
|
||
<li><a class="reference internal" href="#proposal-b-numeric-break-continue">Proposal B - Numeric break & continue</a></li>
|
||
<li><a class="reference internal" href="#proposal-c-the-reduplicative-method">Proposal C - The reduplicative method</a></li>
|
||
<li><a class="reference internal" href="#proposal-d-explicit-iterators">Proposal D - Explicit iterators</a></li>
|
||
<li><a class="reference internal" href="#proposal-e-explicit-iterators-and-iterator-methods">Proposal E - Explicit iterators and iterator methods</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a></li>
|
||
<li><a class="reference internal" href="#footnotes">Footnotes</a></li>
|
||
<li><a class="reference internal" href="#resources">Resources</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
</ul>
|
||
</details></section>
|
||
<section id="rejection-notice">
|
||
<h2><a class="toc-backref" href="#rejection-notice" role="doc-backlink">Rejection Notice</a></h2>
|
||
<p>This PEP is rejected.
|
||
See <a class="reference external" href="https://mail.python.org/pipermail/python-3000/2007-July/008663.html">https://mail.python.org/pipermail/python-3000/2007-July/008663.html</a>.</p>
|
||
</section>
|
||
<section id="abstract">
|
||
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
||
<p>This PEP proposes support for labels in Python’s <code class="docutils literal notranslate"><span class="pre">break</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">continue</span></code> statements. It is inspired by labeled <code class="docutils literal notranslate"><span class="pre">break</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">continue</span></code> in other languages, and the author’s own infrequent but
|
||
persistent need for such a feature.</p>
|
||
</section>
|
||
<section id="introduction">
|
||
<h2><a class="toc-backref" href="#introduction" role="doc-backlink">Introduction</a></h2>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">break</span></code> statement allows the programmer to terminate a loop
|
||
early, and the <code class="docutils literal notranslate"><span class="pre">continue</span></code> statement allows the programmer to move to
|
||
the next iteration of a loop early. In Python currently, <code class="docutils literal notranslate"><span class="pre">break</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">continue</span></code> can apply only to the innermost enclosing loop.</p>
|
||
<p>Adding support for labels to the <code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> statements
|
||
is a logical extension to the existing behavior of the <code class="docutils literal notranslate"><span class="pre">break</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">continue</span></code> statements. Labeled <code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> can
|
||
improve the readability and flexibility of complex code which uses
|
||
nested loops.</p>
|
||
<p>For brevity’s sake, the examples and discussion in this PEP usually
|
||
refers to the <code class="docutils literal notranslate"><span class="pre">break</span></code> statement. However, all of the examples and
|
||
motivations apply equally to labeled <code class="docutils literal notranslate"><span class="pre">continue</span></code>.</p>
|
||
</section>
|
||
<section id="motivation">
|
||
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
||
<p>If the programmer wishes to move to the next iteration of an outer
|
||
enclosing loop, or terminate multiple loops at once, he or she has a
|
||
few less-than elegant options.</p>
|
||
<p>Here’s one common way of imitating labeled <code class="docutils literal notranslate"><span class="pre">break</span></code> in Python (For
|
||
this and future examples, <code class="docutils literal notranslate"><span class="pre">...</span></code> denotes an arbitrary number of
|
||
intervening lines of code):</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">a_list</span><span class="p">:</span>
|
||
<span class="n">time_to_break_out_of_a</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<span class="o">...</span>
|
||
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_list</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_one</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="n">time_to_break_out_of_a</span> <span class="o">=</span> <span class="kc">True</span>
|
||
<span class="k">break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">time_to_break_out_of_a</span><span class="p">:</span>
|
||
<span class="k">break</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This requires five lines and an extra variable,
|
||
<code class="docutils literal notranslate"><span class="pre">time_to_break_out_of_a</span></code>, to keep track of when to break out of the
|
||
outer (a) loop. And those five lines are spread across many lines of
|
||
code, making the control flow difficult to understand.</p>
|
||
<p>This technique is also error-prone. A programmer modifying this code
|
||
might inadvertently put new code after the end of the inner (b) loop
|
||
but before the test for <code class="docutils literal notranslate"><span class="pre">time_to_break_out_of_a</span></code>, instead of after
|
||
the test. This means that code which should have been skipped by
|
||
breaking out of the outer loop gets executed incorrectly.</p>
|
||
<p>This could also be written with an exception. The programmer would
|
||
declare a special exception, wrap the inner loop in a try, and catch
|
||
the exception and break when you see it:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">BreakOutOfALoop</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span> <span class="k">pass</span>
|
||
|
||
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">a_list</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_list</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_one</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">raise</span> <span class="n">BreakOutOfALoop</span>
|
||
<span class="o">...</span>
|
||
<span class="k">except</span> <span class="n">BreakOutOfALoop</span><span class="p">:</span>
|
||
<span class="k">break</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Again, though; this requires five lines and a new, single-purpose
|
||
exception class (instead of a new variable), and spreads basic control
|
||
flow out over many lines. And it breaks out of the inner loop with
|
||
<code class="docutils literal notranslate"><span class="pre">break</span></code> and out of the other loop with an exception, which is
|
||
inelegant. <a class="footnote-reference brackets" href="#toowtdi" id="id1">[1]</a></p>
|
||
<p>This next strategy might be the most elegant solution, assuming
|
||
condition_two() is inexpensive to compute:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">a_list</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_list</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_one</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
|
||
<span class="k">break</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Breaking twice is still inelegant. This implementation also relies on
|
||
the fact that the inner (b) loop bleeds b into the outer for loop,
|
||
which (although explicitly supported) is both surprising to novices,
|
||
and in my opinion counter-intuitive and poor practice.</p>
|
||
<p>The programmer must also still remember to put in both breaks on
|
||
condition two and not insert code before the second break. A single
|
||
conceptual action, breaking out of both loops on condition_two(),
|
||
requires four lines of code at two indentation levels, possibly
|
||
separated by many intervening lines at the end of the inner (b) loop.</p>
|
||
<section id="other-languages">
|
||
<h3><a class="toc-backref" href="#other-languages" role="doc-backlink">Other languages</a></h3>
|
||
<p>Now, put aside whatever dislike you may have for other programming
|
||
languages, and consider the syntax of labeled <code class="docutils literal notranslate"><span class="pre">break</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">continue</span></code>. In Perl:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>ALOOP: foreach $a (@a_array){
|
||
...
|
||
BLOOP: foreach $b (@b_array){
|
||
...
|
||
if (condition_one($a,$b)){
|
||
last BLOOP; # same as plain old last;
|
||
}
|
||
...
|
||
if (condition_two($a,$b)){
|
||
last ALOOP;
|
||
}
|
||
...
|
||
}
|
||
...
|
||
}
|
||
</pre></div>
|
||
</div>
|
||
<p>(Notes: Perl uses <code class="docutils literal notranslate"><span class="pre">last</span></code> instead of <code class="docutils literal notranslate"><span class="pre">break</span></code>. The BLOOP labels
|
||
could be omitted; <code class="docutils literal notranslate"><span class="pre">last</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> apply to the innermost
|
||
loop by default.)</p>
|
||
<p>PHP uses a number denoting the number of loops to break out of, rather
|
||
than a label:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>foreach ($a_array as $a){
|
||
....
|
||
foreach ($b_array as $b){
|
||
....
|
||
if (condition_one($a, $b)){
|
||
break 1; # same as plain old break
|
||
}
|
||
....
|
||
if (condition_two($a, $b)){
|
||
break 2;
|
||
}
|
||
....
|
||
}
|
||
...
|
||
}
|
||
</pre></div>
|
||
</div>
|
||
<p>C/C++, Java, and Ruby all have similar constructions.</p>
|
||
<p>The control flow regarding when to break out of the outer (a) loop is
|
||
fully encapsulated in the <code class="docutils literal notranslate"><span class="pre">break</span></code> statement which gets executed when
|
||
the break condition is satisfied. The depth of the break statement
|
||
does not matter. Control flow is not spread out. No extra variables,
|
||
exceptions, or re-checking or storing of control conditions is
|
||
required. There is no danger that code will get inadvertently
|
||
inserted after the end of the inner (b) loop and before the break
|
||
condition is re-checked inside the outer (a) loop. These are the
|
||
benefits that labeled <code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> would bring to
|
||
Python.</p>
|
||
</section>
|
||
</section>
|
||
<section id="what-this-pep-is-not">
|
||
<h2><a class="toc-backref" href="#what-this-pep-is-not" role="doc-backlink">What this PEP is not</a></h2>
|
||
<p>This PEP is not a proposal to add GOTO to Python. GOTO allows a
|
||
programmer to jump to an arbitrary block or line of code, and
|
||
generally makes control flow more difficult to follow. Although
|
||
<code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> (with or without support for labels) can be
|
||
considered a type of GOTO, it is much more restricted. Another Python
|
||
construct, <code class="docutils literal notranslate"><span class="pre">yield</span></code>, could also be considered a form of GOTO – an
|
||
even less restrictive one. The goal of this PEP is to propose an
|
||
extension to the existing control flow tools <code class="docutils literal notranslate"><span class="pre">break</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">continue</span></code>, to make control flow easier to understand, not more
|
||
difficult.</p>
|
||
<p>Labeled <code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> cannot transfer control to another
|
||
function or method. They cannot even transfer control to an arbitrary
|
||
line of code in the current scope. Currently, they can only affect
|
||
the behavior of a loop, and are quite different and much more
|
||
restricted than GOTO. This extension allows them to affect any
|
||
enclosing loop in the current name-space, but it does not change their
|
||
behavior to that of GOTO.</p>
|
||
</section>
|
||
<section id="specification">
|
||
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
|
||
<p>Under all of these proposals, <code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> by themselves
|
||
will continue to behave as they currently do, applying to the
|
||
innermost loop by default.</p>
|
||
<section id="proposal-a-explicit-labels">
|
||
<h3><a class="toc-backref" href="#proposal-a-explicit-labels" role="doc-backlink">Proposal A - Explicit labels</a></h3>
|
||
<p>The for and while loop syntax will be followed by an optional <code class="docutils literal notranslate"><span class="pre">as</span></code>
|
||
or <code class="docutils literal notranslate"><span class="pre">label</span></code> (contextual) keyword <a class="footnote-reference brackets" href="#keyword" id="id2">[2]</a> and then an identifier,
|
||
which may be used to identify the loop out of which to break (or which
|
||
should be continued).</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">break</span></code> (and <code class="docutils literal notranslate"><span class="pre">continue</span></code>) statements will be followed by an
|
||
optional identifier that refers to the loop out of which to break (or
|
||
which should be continued). Here is an example using the <code class="docutils literal notranslate"><span class="pre">as</span></code>
|
||
keyword:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">a_list</span> <span class="k">as</span> <span class="n">a_loop</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_list</span> <span class="k">as</span> <span class="n">b_loop</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_one</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="n">b_loop</span> <span class="c1"># same as plain old break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="n">a_loop</span>
|
||
<span class="o">...</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Or, with <code class="docutils literal notranslate"><span class="pre">label</span></code> instead of <code class="docutils literal notranslate"><span class="pre">as</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">a_list</span> <span class="n">label</span> <span class="n">a_loop</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_list</span> <span class="n">label</span> <span class="n">b_loop</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_one</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="n">b_loop</span> <span class="c1"># same as plain old break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="n">a_loop</span>
|
||
<span class="o">...</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This has all the benefits outlined above. It requires modifications
|
||
to the language syntax: the syntax of <code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code>
|
||
syntax statements and for and while statements. It requires either a
|
||
new conditional keyword <code class="docutils literal notranslate"><span class="pre">label</span></code> or an extension to the conditional
|
||
keyword <code class="docutils literal notranslate"><span class="pre">as</span></code>. <a class="footnote-reference brackets" href="#as" id="id3">[3]</a> It is unlikely to require any changes to
|
||
existing Python programs. Passing an identifier not defined in the
|
||
local scope to <code class="docutils literal notranslate"><span class="pre">break</span></code> or <code class="docutils literal notranslate"><span class="pre">continue</span></code> would raise a NameError.</p>
|
||
</section>
|
||
<section id="proposal-b-numeric-break-continue">
|
||
<h3><a class="toc-backref" href="#proposal-b-numeric-break-continue" role="doc-backlink">Proposal B - Numeric break & continue</a></h3>
|
||
<p>Rather than altering the syntax of <code class="docutils literal notranslate"><span class="pre">for</span></code> and <code class="docutils literal notranslate"><span class="pre">while</span></code> loops,
|
||
<code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> would take a numeric argument denoting the
|
||
enclosing loop which is being controlled, similar to PHP.</p>
|
||
<p>It seems more Pythonic to me for <code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> to refer
|
||
to loops indexing from zero, as opposed to indexing from one as PHP
|
||
does.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">a_list</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_list</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_one</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="mi">0</span> <span class="c1"># same as plain old break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="mi">1</span>
|
||
<span class="o">...</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Passing a number that was too large, or less than zero, or non-integer
|
||
to <code class="docutils literal notranslate"><span class="pre">break</span></code> or <code class="docutils literal notranslate"><span class="pre">continue</span></code> would (probably) raise an IndexError.</p>
|
||
<p>This proposal would not require any changes to existing Python
|
||
programs.</p>
|
||
</section>
|
||
<section id="proposal-c-the-reduplicative-method">
|
||
<h3><a class="toc-backref" href="#proposal-c-the-reduplicative-method" role="doc-backlink">Proposal C - The reduplicative method</a></h3>
|
||
<p>The syntax of <code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code> would be altered to allow
|
||
multiple <code class="docutils literal notranslate"><span class="pre">break</span></code> and continue statements on the same line. Thus,
|
||
<code class="docutils literal notranslate"><span class="pre">break</span> <span class="pre">break</span></code> would break out of the first and second enclosing
|
||
loops.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">a_list</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_list</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_one</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="c1"># plain old break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="k">break</span>
|
||
<span class="o">...</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This would also allow the programmer to break out of the inner loop
|
||
and continue the next outermost simply by writing <code class="docutils literal notranslate"><span class="pre">break</span> <span class="pre">continue</span></code>,
|
||
<a class="footnote-reference brackets" href="#breakcontinue" id="id4">[4]</a> and so on. I’m not sure what exception would be
|
||
raised if the programmer used more <code class="docutils literal notranslate"><span class="pre">break</span></code> or <code class="docutils literal notranslate"><span class="pre">continue</span></code>
|
||
statements than existing loops (perhaps a SyntaxError?).</p>
|
||
<p>I expect this proposal to get rejected because it will be judged too
|
||
difficult to understand.</p>
|
||
<p>This proposal would not require any changes to existing Python
|
||
programs.</p>
|
||
</section>
|
||
<section id="proposal-d-explicit-iterators">
|
||
<h3><a class="toc-backref" href="#proposal-d-explicit-iterators" role="doc-backlink">Proposal D - Explicit iterators</a></h3>
|
||
<p>Rather than embellishing for and while loop syntax with labels, the
|
||
programmer wishing to use labeled breaks would be required to create
|
||
the iterator explicitly and assign it to an identifier if he or she
|
||
wanted to <code class="docutils literal notranslate"><span class="pre">break</span></code> out of or <code class="docutils literal notranslate"><span class="pre">continue</span></code> that loop from within a
|
||
deeper loop.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a_iter</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">a_list</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">a_iter</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="n">b_iter</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">b_list</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_iter</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_one</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="n">b_iter</span> <span class="c1"># same as plain old break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
|
||
<span class="k">break</span> <span class="n">a_iter</span>
|
||
<span class="o">...</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Passing a non-iterator object to <code class="docutils literal notranslate"><span class="pre">break</span></code> or <code class="docutils literal notranslate"><span class="pre">continue</span></code> would raise
|
||
a TypeError; and a nonexistent identifier would raise a NameError.
|
||
This proposal requires only one extra line to create a labeled loop,
|
||
and no extra lines to break out of a containing loop, and no changes
|
||
to existing Python programs.</p>
|
||
</section>
|
||
<section id="proposal-e-explicit-iterators-and-iterator-methods">
|
||
<h3><a class="toc-backref" href="#proposal-e-explicit-iterators-and-iterator-methods" role="doc-backlink">Proposal E - Explicit iterators and iterator methods</a></h3>
|
||
<p>This is a variant of Proposal D. Iterators would need be created
|
||
explicitly if anything other that the most basic use of <code class="docutils literal notranslate"><span class="pre">break</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">continue</span></code> was required. Instead of modifying the syntax of
|
||
<code class="docutils literal notranslate"><span class="pre">break</span></code> and <code class="docutils literal notranslate"><span class="pre">continue</span></code>, <code class="docutils literal notranslate"><span class="pre">.break()</span></code> and <code class="docutils literal notranslate"><span class="pre">.continue()</span></code> methods
|
||
could be added to the Iterator type.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a_iter</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">a_list</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">a_iter</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="n">b_iter</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">b_list</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">b_iter</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_one</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
|
||
<span class="n">b_iter</span><span class="o">.</span><span class="k">break</span><span class="p">()</span> <span class="c1"># same as plain old break</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition_two</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
|
||
<span class="n">a_iter</span><span class="o">.</span><span class="k">break</span><span class="p">()</span>
|
||
<span class="o">...</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>I expect that this proposal will get rejected on the grounds of sheer
|
||
ugliness. However, it requires no changes to the language syntax
|
||
whatsoever, nor does it require any changes to existing Python
|
||
programs.</p>
|
||
</section>
|
||
</section>
|
||
<section id="implementation">
|
||
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
|
||
<p>I have never looked at the Python language implementation itself, so I
|
||
have no idea how difficult this would be to implement. If this PEP is
|
||
accepted, but no one is available to write the feature, I will try to
|
||
implement it myself.</p>
|
||
</section>
|
||
<section id="footnotes">
|
||
<h2><a class="toc-backref" href="#footnotes" role="doc-backlink">Footnotes</a></h2>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="toowtdi" role="doc-footnote">
|
||
<dt class="label" id="toowtdi">[<a href="#id1">1</a>]</dt>
|
||
<dd>Breaking some loops with exceptions is inelegant because
|
||
it’s a violation of There’s Only One Way To Do It.</aside>
|
||
<aside class="footnote brackets" id="keyword" role="doc-footnote">
|
||
<dt class="label" id="keyword">[<a href="#id2">2</a>]</dt>
|
||
<dd>Or really any new contextual keyword that the community
|
||
likes: <code class="docutils literal notranslate"><span class="pre">as</span></code>, <code class="docutils literal notranslate"><span class="pre">label</span></code>, <code class="docutils literal notranslate"><span class="pre">labeled</span></code>, <code class="docutils literal notranslate"><span class="pre">loop</span></code>, <code class="docutils literal notranslate"><span class="pre">name</span></code>, <code class="docutils literal notranslate"><span class="pre">named</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">walrus</span></code>, whatever.</aside>
|
||
<aside class="footnote brackets" id="as" role="doc-footnote">
|
||
<dt class="label" id="as">[<a href="#id3">3</a>]</dt>
|
||
<dd>The use of <code class="docutils literal notranslate"><span class="pre">as</span></code> in a similar context has been proposed here,
|
||
<a class="reference external" href="http://sourceforge.net/tracker/index.php?func=detail&aid=1714448&group_id=5470&atid=355470">http://sourceforge.net/tracker/index.php?func=detail&aid=1714448&group_id=5470&atid=355470</a>
|
||
but to my knowledge this idea has not been written up as a PEP.</aside>
|
||
<aside class="footnote brackets" id="breakcontinue" role="doc-footnote">
|
||
<dt class="label" id="breakcontinue">[<a href="#id4">4</a>]</dt>
|
||
<dd>To continue the Nth outer loop, you would write
|
||
break N-1 times and then continue. Only one <code class="docutils literal notranslate"><span class="pre">continue</span></code> would be
|
||
allowed, and only at the end of a sequence of breaks. <code class="docutils literal notranslate"><span class="pre">continue</span>
|
||
<span class="pre">break</span></code> or <code class="docutils literal notranslate"><span class="pre">continue</span> <span class="pre">continue</span></code> makes no sense.</aside>
|
||
</aside>
|
||
</section>
|
||
<section id="resources">
|
||
<h2><a class="toc-backref" href="#resources" role="doc-backlink">Resources</a></h2>
|
||
<p>This issue has come up before, although it has never been resolved, to
|
||
my knowledge.</p>
|
||
<ul class="simple">
|
||
<li><a class="reference external" href="http://groups.google.com/group/comp.lang.python/browse_thread/thread/6da848f762c9cf58/979ca3cd42633b52?lnk=gst&q=labeled+break&rnum=3#979ca3cd42633b52">labeled breaks</a>, on comp.lang.python, in the context of
|
||
<code class="docutils literal notranslate"><span class="pre">do...while</span></code> loops</li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-list/1999-September/#11080">break LABEL vs. exceptions + PROPOSAL</a>, on python-list, as
|
||
compared to using Exceptions for flow control</li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-list/2001-April/#78439">Named code blocks</a> on python-list, a suggestion motivated by the
|
||
desire for labeled break / continue</li>
|
||
<li><a class="reference external" href="http://mail-archives.apache.org/mod_mbox/httpd-python-cvs/200511.mbox/%3C20051112204322.4010.qmail@minotaur.apache.org%3E">mod_python bug fix</a> An example of someone setting a flag inside
|
||
an inner loop that triggers a continue in the containing loop, to
|
||
work around the absence of labeled break and continue</li>
|
||
</ul>
|
||
</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-3136.rst">https://github.com/python/peps/blob/main/peps/pep-3136.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-3136.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="#rejection-notice">Rejection Notice</a></li>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#introduction">Introduction</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#other-languages">Other languages</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#what-this-pep-is-not">What this PEP is not</a></li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#proposal-a-explicit-labels">Proposal A - Explicit labels</a></li>
|
||
<li><a class="reference internal" href="#proposal-b-numeric-break-continue">Proposal B - Numeric break & continue</a></li>
|
||
<li><a class="reference internal" href="#proposal-c-the-reduplicative-method">Proposal C - The reduplicative method</a></li>
|
||
<li><a class="reference internal" href="#proposal-d-explicit-iterators">Proposal D - Explicit iterators</a></li>
|
||
<li><a class="reference internal" href="#proposal-e-explicit-iterators-and-iterator-methods">Proposal E - Explicit iterators and iterator methods</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a></li>
|
||
<li><a class="reference internal" href="#footnotes">Footnotes</a></li>
|
||
<li><a class="reference internal" href="#resources">Resources</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-3136.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> |