557 lines
41 KiB
HTML
557 lines
41 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 308 – Conditional Expressions | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0308/">
|
||
<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 308 – Conditional Expressions | peps.python.org'>
|
||
<meta property="og:description" content="Python Enhancement Proposals (PEPs)">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0308/">
|
||
<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 308</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 308 – Conditional Expressions</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Guido van Rossum, Raymond Hettinger</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">07-Feb-2003</dd>
|
||
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-odd">2.5</dd>
|
||
<dt class="field-even">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-even">07-Feb-2003, 11-Feb-2003</dd>
|
||
</dl>
|
||
<hr class="docutils" />
|
||
<section id="contents">
|
||
<details><summary>Table of Contents</summary><ul class="simple">
|
||
<li><a class="reference internal" href="#adding-a-conditional-expression">Adding a conditional expression</a></li>
|
||
<li><a class="reference internal" href="#references">References</a></li>
|
||
<li><a class="reference internal" href="#introduction-to-earlier-draft-of-the-pep-kept-for-historical-purposes">Introduction to earlier draft of the PEP (kept for historical purposes)</a></li>
|
||
<li><a class="reference internal" href="#proposal">Proposal</a></li>
|
||
<li><a class="reference internal" href="#alternatives">Alternatives</a></li>
|
||
<li><a class="reference internal" href="#summary-of-the-current-state-of-the-discussion">Summary of the Current State of the Discussion</a></li>
|
||
<li><a class="reference internal" href="#short-circuit-behavior">Short-Circuit Behavior</a></li>
|
||
<li><a class="reference internal" href="#detailed-results-of-voting">Detailed Results of Voting</a><ul>
|
||
<li><a class="reference internal" href="#choice-key">CHOICE KEY</a></li>
|
||
<li><a class="reference internal" href="#detail-for-write-in-votes-and-their-ranking">Detail for write-in votes and their ranking</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
</ul>
|
||
</details></section>
|
||
<section id="adding-a-conditional-expression">
|
||
<h2><a class="toc-backref" href="#adding-a-conditional-expression" role="doc-backlink">Adding a conditional expression</a></h2>
|
||
<p>On 9/29/2005, Guido decided to add conditional expressions in the
|
||
form of “X if C else Y”. <a class="footnote-reference brackets" href="#id4" id="id1">[1]</a></p>
|
||
<p>The motivating use case was the prevalence of error-prone attempts
|
||
to achieve the same effect using “and” and “or”. <a class="footnote-reference brackets" href="#id5" id="id2">[2]</a></p>
|
||
<p>Previous community efforts to add a conditional expression were
|
||
stymied by a lack of consensus on the best syntax. That issue was
|
||
resolved by simply deferring to a BDFL best judgment call.</p>
|
||
<p>The decision was validated by reviewing how the syntax fared when
|
||
applied throughout the standard library (this review approximates a
|
||
sampling of real-world use cases, across a variety of applications,
|
||
written by a number of programmers with diverse backgrounds). <a class="footnote-reference brackets" href="#id6" id="id3">[3]</a></p>
|
||
<p>The following change will be made to the grammar. (The or_test
|
||
symbols is new, the others are modified.)</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">test</span><span class="p">:</span> <span class="n">or_test</span> <span class="p">[</span><span class="s1">'if'</span> <span class="n">or_test</span> <span class="s1">'else'</span> <span class="n">test</span><span class="p">]</span> <span class="o">|</span> <span class="n">lambdef</span>
|
||
<span class="n">or_test</span><span class="p">:</span> <span class="n">and_test</span> <span class="p">(</span><span class="s1">'or'</span> <span class="n">and_test</span><span class="p">)</span><span class="o">*</span>
|
||
<span class="o">...</span>
|
||
<span class="n">testlist_safe</span><span class="p">:</span> <span class="n">or_test</span> <span class="p">[(</span><span class="s1">','</span> <span class="n">or_test</span><span class="p">)</span><span class="o">+</span> <span class="p">[</span><span class="s1">','</span><span class="p">]]</span>
|
||
<span class="o">...</span>
|
||
<span class="n">gen_for</span><span class="p">:</span> <span class="s1">'for'</span> <span class="n">exprlist</span> <span class="s1">'in'</span> <span class="n">or_test</span> <span class="p">[</span><span class="n">gen_iter</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The new syntax nearly introduced a minor syntactical backwards
|
||
incompatibility. In previous Python versions, the following is
|
||
legal:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">if</span> <span class="n">f</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>(I.e. a list comprehension where the sequence following ‘in’ is an
|
||
unparenthesized series of lambdas – or just one lambda, even.)</p>
|
||
<p>In Python 3.0, the series of lambdas will have to be
|
||
parenthesized, e.g.:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> <span class="k">if</span> <span class="n">f</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This is because lambda binds less tight than the if-else
|
||
expression, but in this context, the lambda could already be
|
||
followed by an ‘if’ keyword that binds less tightly still (for
|
||
details, consider the grammar changes shown above).</p>
|
||
<p>However, in Python 2.5, a slightly different grammar is used that
|
||
is more backwards compatible, but constrains the grammar of a
|
||
lambda used in this position by forbidding the lambda’s body to
|
||
contain an unparenthesized condition expression. Examples:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="k">if</span> <span class="n">x</span> <span class="o">>=</span> <span class="mi">0</span> <span class="k">else</span> <span class="o">-</span><span class="mi">1</span><span class="p">)]</span> <span class="c1"># OK</span>
|
||
<span class="p">[</span><span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="mi">1</span><span class="p">,</span> <span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="k">if</span> <span class="n">x</span> <span class="o">>=</span> <span class="mi">0</span> <span class="k">else</span> <span class="o">-</span><span class="mi">1</span><span class="p">)]</span> <span class="c1"># OK</span>
|
||
<span class="p">[</span><span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="mi">1</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="p">(</span><span class="n">x</span> <span class="k">if</span> <span class="n">x</span> <span class="o">>=</span> <span class="mi">0</span> <span class="k">else</span> <span class="o">-</span><span class="mi">1</span><span class="p">)]</span> <span class="c1"># OK</span>
|
||
<span class="p">[</span><span class="n">f</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="mi">1</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="k">if</span> <span class="n">x</span> <span class="o">>=</span> <span class="mi">0</span> <span class="k">else</span> <span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="c1"># INVALID</span>
|
||
</pre></div>
|
||
</div>
|
||
</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="id4" role="doc-footnote">
|
||
<dt class="label" id="id4">[<a href="#id1">1</a>]</dt>
|
||
<dd>Pronouncement
|
||
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2005-September/056846.html">https://mail.python.org/pipermail/python-dev/2005-September/056846.html</a></aside>
|
||
<aside class="footnote brackets" id="id5" role="doc-footnote">
|
||
<dt class="label" id="id5">[<a href="#id2">2</a>]</dt>
|
||
<dd>Motivating use case:
|
||
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2005-September/056546.html">https://mail.python.org/pipermail/python-dev/2005-September/056546.html</a>
|
||
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2005-September/056510.html">https://mail.python.org/pipermail/python-dev/2005-September/056510.html</a></aside>
|
||
<aside class="footnote brackets" id="id6" role="doc-footnote">
|
||
<dt class="label" id="id6">[<a href="#id3">3</a>]</dt>
|
||
<dd>Review in the context of real-world code fragments:
|
||
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2005-September/056803.html">https://mail.python.org/pipermail/python-dev/2005-September/056803.html</a></aside>
|
||
</aside>
|
||
</section>
|
||
<section id="introduction-to-earlier-draft-of-the-pep-kept-for-historical-purposes">
|
||
<h2><a class="toc-backref" href="#introduction-to-earlier-draft-of-the-pep-kept-for-historical-purposes" role="doc-backlink">Introduction to earlier draft of the PEP (kept for historical purposes)</a></h2>
|
||
<p>Requests for an if-then-else (“ternary”) expression keep coming up
|
||
on comp.lang.python. This PEP contains a concrete proposal of a
|
||
fairly Pythonic syntax. This is the community’s one chance: if
|
||
this PEP is approved with a clear majority, it will be implemented
|
||
in Python 2.4. If not, the PEP will be augmented with a summary
|
||
of the reasons for rejection and the subject better not come up
|
||
again. While the BDFL is co-author of this PEP, he is neither in
|
||
favor nor against this proposal; it is up to the community to
|
||
decide. If the community can’t decide, the BDFL will reject the
|
||
PEP.</p>
|
||
<p>After unprecedented community response (very good arguments were
|
||
made both pro and con) this PEP has been revised with the help of
|
||
Raymond Hettinger. Without going through a complete revision
|
||
history, the main changes are a different proposed syntax, an
|
||
overview of proposed alternatives, the state of the current
|
||
discussion, and a discussion of short-circuit behavior.</p>
|
||
<p>Following the discussion, a vote was held. While there was an overall
|
||
interest in having some form of if-then-else expressions, no one
|
||
format was able to draw majority support. Accordingly, the PEP was
|
||
rejected due to the lack of an overwhelming majority for change.
|
||
Also, a Python design principle has been to prefer the status quo
|
||
whenever there are doubts about which path to take.</p>
|
||
</section>
|
||
<section id="proposal">
|
||
<h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2>
|
||
<p>The proposed syntax is as follows:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="k">if</span> <span class="o"><</span><span class="n">condition</span><span class="o">></span><span class="p">:</span> <span class="o"><</span><span class="n">expression1</span><span class="o">></span> <span class="k">else</span><span class="p">:</span> <span class="o"><</span><span class="n">expression2</span><span class="o">></span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that the enclosing parentheses are not optional.</p>
|
||
<p>The resulting expression is evaluated like this:</p>
|
||
<ul class="simple">
|
||
<li>First, <condition> is evaluated.</li>
|
||
<li>If <condition> is true, <expression1> is evaluated and is the
|
||
result of the whole thing.</li>
|
||
<li>If <condition> is false, <expression2> is evaluated and is the
|
||
result of the whole thing.</li>
|
||
</ul>
|
||
<p>A natural extension of this syntax is to allow one or more ‘elif’
|
||
parts:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="k">if</span> <span class="o"><</span><span class="n">cond1</span><span class="o">></span><span class="p">:</span> <span class="o"><</span><span class="n">expr1</span><span class="o">></span> <span class="k">elif</span> <span class="o"><</span><span class="n">cond2</span><span class="o">></span><span class="p">:</span> <span class="o"><</span><span class="n">expr2</span><span class="o">></span> <span class="o">...</span> <span class="k">else</span><span class="p">:</span> <span class="o"><</span><span class="n">exprN</span><span class="o">></span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This will be implemented if the proposal is accepted.</p>
|
||
<p>The downsides to the proposal are:</p>
|
||
<ul class="simple">
|
||
<li>the required parentheses</li>
|
||
<li>confusability with statement syntax</li>
|
||
<li>additional semantic loading of colons</li>
|
||
</ul>
|
||
<p>Note that at most one of <expression1> and <expression2> is
|
||
evaluated. This is called a “short-circuit expression”; it is
|
||
similar to the way the second operand of ‘and’ / ‘or’ is only
|
||
evaluated if the first operand is true / false.</p>
|
||
<p>A common way to emulate an if-then-else expression is:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="n">condition</span><span class="o">></span> <span class="ow">and</span> <span class="o"><</span><span class="n">expression1</span><span class="o">></span> <span class="ow">or</span> <span class="o"><</span><span class="n">expression2</span><span class="o">></span>
|
||
</pre></div>
|
||
</div>
|
||
<p>However, this doesn’t work the same way: it returns <expression2>
|
||
when <expression1> is false! See FAQ 4.16 for alternatives that
|
||
work – however, they are pretty ugly and require much more effort
|
||
to understand.</p>
|
||
</section>
|
||
<section id="alternatives">
|
||
<h2><a class="toc-backref" href="#alternatives" role="doc-backlink">Alternatives</a></h2>
|
||
<p>Holger Krekel proposed a new, minimally invasive variant:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="n">condition</span><span class="o">></span> <span class="ow">and</span> <span class="o"><</span><span class="n">expression1</span><span class="o">></span> <span class="k">else</span> <span class="o"><</span><span class="n">expression2</span><span class="o">></span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The concept behind it is that a nearly complete ternary operator
|
||
already exists with and/or and this proposal is the least invasive
|
||
change that makes it complete. Many respondants on the
|
||
newsgroup found this to be the most pleasing alternative.
|
||
However, a couple of respondants were able to post examples
|
||
that were mentally difficult to parse. Later it was pointed
|
||
out that this construct works by having the “else” change the
|
||
existing meaning of “and”.</p>
|
||
<p>As a result, there is increasing support for Christian Tismer’s
|
||
proposed variant of the same idea:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="n">condition</span><span class="o">></span> <span class="n">then</span> <span class="o"><</span><span class="n">expression1</span><span class="o">></span> <span class="k">else</span> <span class="o"><</span><span class="n">expression2</span><span class="o">></span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The advantages are simple visual parsing, no required parentheses,
|
||
no change in the semantics of existing keywords, not as likely
|
||
as the proposal to be confused with statement syntax, and does
|
||
not further overload the colon. The disadvantage is the
|
||
implementation costs of introducing a new keyword. However,
|
||
unlike other new keywords, the word “then” seems unlikely to
|
||
have been used as a name in existing programs.</p>
|
||
<p>—</p>
|
||
<p>Many C-derived languages use this syntax:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><condition> ? <expression1> : <expression2>
|
||
</pre></div>
|
||
</div>
|
||
<p>Eric Raymond even implemented this. The BDFL rejected this for
|
||
several reasons: the colon already has many uses in Python (even
|
||
though it would actually not be ambiguous, because the question
|
||
mark requires a matching colon); for people not used to C-derived
|
||
language, it is hard to understand.</p>
|
||
<p>—</p>
|
||
<p>The original version of this PEP proposed the following syntax:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="n">expression1</span><span class="o">></span> <span class="k">if</span> <span class="o"><</span><span class="n">condition</span><span class="o">></span> <span class="k">else</span> <span class="o"><</span><span class="n">expression2</span><span class="o">></span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The out-of-order arrangement was found to be too uncomfortable
|
||
for many of participants in the discussion; especially when
|
||
<expression1> is long, it’s easy to miss the conditional while
|
||
skimming.</p>
|
||
<p>—</p>
|
||
<p>Some have suggested adding a new builtin instead of extending the
|
||
syntax of the language. For example:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cond</span><span class="p">(</span><span class="o"><</span><span class="n">condition</span><span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="n">expression1</span><span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="n">expression2</span><span class="o">></span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This won’t work the way a syntax extension will because both
|
||
expression1 and expression2 must be evaluated before the function
|
||
is called. There’s no way to short-circuit the expression
|
||
evaluation. It could work if ‘cond’ (or some other name) were
|
||
made a keyword, but that has all the disadvantages of adding a new
|
||
keyword, plus confusing syntax: it <strong>looks</strong> like a function call so
|
||
a casual reader might expect both <expression1> and <expression2>
|
||
to be evaluated.</p>
|
||
</section>
|
||
<section id="summary-of-the-current-state-of-the-discussion">
|
||
<h2><a class="toc-backref" href="#summary-of-the-current-state-of-the-discussion" role="doc-backlink">Summary of the Current State of the Discussion</a></h2>
|
||
<p>Groups are falling into one of three camps:</p>
|
||
<ol class="arabic">
|
||
<li>Adopt a ternary operator built using punctuation characters:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><condition> ? <expression1> : <expression2>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Adopt a ternary operator built using new or existing keywords.
|
||
The leading examples are:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o"><</span><span class="n">condition</span><span class="o">></span> <span class="n">then</span> <span class="o"><</span><span class="n">expression1</span><span class="o">></span> <span class="k">else</span> <span class="o"><</span><span class="n">expression2</span><span class="o">></span>
|
||
<span class="p">(</span><span class="k">if</span> <span class="o"><</span><span class="n">condition</span><span class="o">></span><span class="p">:</span> <span class="o"><</span><span class="n">expression1</span><span class="o">></span> <span class="k">else</span><span class="p">:</span> <span class="o"><</span><span class="n">expression2</span><span class="o">></span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Do nothing.</li>
|
||
</ol>
|
||
<p>The first two positions are relatively similar.</p>
|
||
<p>Some find that any form of punctuation makes the language more
|
||
cryptic. Others find that punctuation style is appropriate for
|
||
expressions rather than statements and helps avoid a COBOL style:
|
||
3 plus 4 times 5.</p>
|
||
<p>Adapting existing keywords attempts to improve on punctuation
|
||
through explicit meaning and a more tidy appearance. The downside
|
||
is some loss of the economy-of-expression provided by punctuation
|
||
operators. The other downside is that it creates some degree of
|
||
confusion between the two meanings and two usages of the keywords.</p>
|
||
<p>Those difficulties are overcome by options which introduce new
|
||
keywords which take more effort to implement.</p>
|
||
<p>The last position is doing nothing. Arguments in favor include
|
||
keeping the language simple and concise; maintaining backwards
|
||
compatibility; and that any every use case can already be already
|
||
expressed in terms of “if” and “else”. Lambda expressions are an
|
||
exception as they require the conditional to be factored out into
|
||
a separate function definition.</p>
|
||
<p>The arguments against doing nothing are that the other choices
|
||
allow greater economy of expression and that current practices
|
||
show a propensity for erroneous uses of “and”, “or”, or one their
|
||
more complex, less visually unappealing workarounds.</p>
|
||
</section>
|
||
<section id="short-circuit-behavior">
|
||
<h2><a class="toc-backref" href="#short-circuit-behavior" role="doc-backlink">Short-Circuit Behavior</a></h2>
|
||
<p>The principal difference between the ternary operator and the
|
||
<code class="docutils literal notranslate"><span class="pre">cond()</span></code> function is that the latter provides an expression form but
|
||
does not provide short-circuit evaluation.</p>
|
||
<p>Short-circuit evaluation is desirable on three occasions:</p>
|
||
<ol class="arabic simple">
|
||
<li>When an expression has side-effects</li>
|
||
<li>When one or both of the expressions are resource intensive</li>
|
||
<li>When the condition serves as a guard for the validity of the
|
||
expression.</li>
|
||
</ol>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span># Example where all three reasons apply
|
||
data = isinstance(source, file) ? source.readlines()
|
||
: source.split()
|
||
</pre></div>
|
||
</div>
|
||
<ol class="arabic simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">readlines()</span></code> moves the file pointer</li>
|
||
<li>for long sources, both alternatives take time</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">split()</span></code> is only valid for strings and <code class="docutils literal notranslate"><span class="pre">readlines()</span></code> is only
|
||
valid for file objects.</li>
|
||
</ol>
|
||
<p>Supporters of a <code class="docutils literal notranslate"><span class="pre">cond()</span></code> function point out that the need for
|
||
short-circuit evaluation is rare. Scanning through existing code
|
||
directories, they found that if/else did not occur often; and of
|
||
those only a few contained expressions that could be helped by
|
||
<code class="docutils literal notranslate"><span class="pre">cond()</span></code> or a ternary operator; and that most of those had no need
|
||
for short-circuit evaluation. Hence, <code class="docutils literal notranslate"><span class="pre">cond()</span></code> would suffice for
|
||
most needs and would spare efforts to alter the syntax of the
|
||
language.</p>
|
||
<p>More supporting evidence comes from scans of C code bases which
|
||
show that its ternary operator used very rarely (as a percentage
|
||
of lines of code).</p>
|
||
<p>A counterpoint to that analysis is that the availability of a
|
||
ternary operator helped the programmer in every case because it
|
||
spared the need to search for side-effects. Further, it would
|
||
preclude errors arising from distant modifications which introduce
|
||
side-effects. The latter case has become more of a reality with
|
||
the advent of properties where even attribute access can be given
|
||
side-effects.</p>
|
||
<p>The BDFL’s position is that short-circuit behavior is essential
|
||
for an if-then-else construct to be added to the language.</p>
|
||
</section>
|
||
<section id="detailed-results-of-voting">
|
||
<h2><a class="toc-backref" href="#detailed-results-of-voting" role="doc-backlink">Detailed Results of Voting</a></h2>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Votes</span> <span class="n">rejecting</span> <span class="nb">all</span> <span class="n">options</span><span class="p">:</span> <span class="mi">82</span>
|
||
<span class="n">Votes</span> <span class="k">with</span> <span class="n">rank</span> <span class="n">ordering</span><span class="p">:</span> <span class="mi">436</span>
|
||
<span class="o">---</span>
|
||
<span class="n">Total</span> <span class="n">votes</span> <span class="n">received</span><span class="p">:</span> <span class="mi">518</span>
|
||
|
||
|
||
<span class="n">ACCEPT</span> <span class="n">REJECT</span> <span class="n">TOTAL</span>
|
||
<span class="o">---------------------</span> <span class="o">---------------------</span> <span class="o">-----</span>
|
||
<span class="n">Rank1</span> <span class="n">Rank2</span> <span class="n">Rank3</span> <span class="n">Rank1</span> <span class="n">Rank2</span> <span class="n">Rank3</span>
|
||
<span class="n">Letter</span>
|
||
<span class="n">A</span> <span class="mi">51</span> <span class="mi">33</span> <span class="mi">19</span> <span class="mi">18</span> <span class="mi">20</span> <span class="mi">20</span> <span class="mi">161</span>
|
||
<span class="n">B</span> <span class="mi">45</span> <span class="mi">46</span> <span class="mi">21</span> <span class="mi">9</span> <span class="mi">24</span> <span class="mi">23</span> <span class="mi">168</span>
|
||
<span class="n">C</span> <span class="mi">94</span> <span class="mi">54</span> <span class="mi">29</span> <span class="mi">20</span> <span class="mi">20</span> <span class="mi">18</span> <span class="mi">235</span>
|
||
<span class="n">D</span> <span class="mi">71</span> <span class="mi">40</span> <span class="mi">31</span> <span class="mi">5</span> <span class="mi">28</span> <span class="mi">31</span> <span class="mi">206</span>
|
||
<span class="n">E</span> <span class="mi">7</span> <span class="mi">7</span> <span class="mi">10</span> <span class="mi">3</span> <span class="mi">5</span> <span class="mi">32</span>
|
||
<span class="n">F</span> <span class="mi">14</span> <span class="mi">19</span> <span class="mi">10</span> <span class="mi">7</span> <span class="mi">17</span> <span class="mi">67</span>
|
||
<span class="n">G</span> <span class="mi">7</span> <span class="mi">6</span> <span class="mi">10</span> <span class="mi">1</span> <span class="mi">2</span> <span class="mi">4</span> <span class="mi">30</span>
|
||
<span class="n">H</span> <span class="mi">20</span> <span class="mi">22</span> <span class="mi">17</span> <span class="mi">4</span> <span class="mi">10</span> <span class="mi">25</span> <span class="mi">98</span>
|
||
<span class="n">I</span> <span class="mi">16</span> <span class="mi">20</span> <span class="mi">9</span> <span class="mi">5</span> <span class="mi">5</span> <span class="mi">20</span> <span class="mi">75</span>
|
||
<span class="n">J</span> <span class="mi">6</span> <span class="mi">17</span> <span class="mi">5</span> <span class="mi">1</span> <span class="mi">10</span> <span class="mi">39</span>
|
||
<span class="n">K</span> <span class="mi">1</span> <span class="mi">6</span> <span class="mi">4</span> <span class="mi">13</span> <span class="mi">24</span>
|
||
<span class="n">L</span> <span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">3</span> <span class="mi">9</span>
|
||
<span class="n">M</span> <span class="mi">7</span> <span class="mi">3</span> <span class="mi">4</span> <span class="mi">2</span> <span class="mi">5</span> <span class="mi">11</span> <span class="mi">32</span>
|
||
<span class="n">N</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span> <span class="mi">2</span> <span class="mi">11</span>
|
||
<span class="n">O</span> <span class="mi">1</span> <span class="mi">6</span> <span class="mi">5</span> <span class="mi">1</span> <span class="mi">4</span> <span class="mi">9</span> <span class="mi">26</span>
|
||
<span class="n">P</span> <span class="mi">5</span> <span class="mi">3</span> <span class="mi">6</span> <span class="mi">1</span> <span class="mi">5</span> <span class="mi">7</span> <span class="mi">27</span>
|
||
<span class="n">Q</span> <span class="mi">18</span> <span class="mi">7</span> <span class="mi">15</span> <span class="mi">6</span> <span class="mi">5</span> <span class="mi">11</span> <span class="mi">62</span>
|
||
<span class="n">Z</span> <span class="mi">1</span> <span class="mi">1</span>
|
||
<span class="o">---</span> <span class="o">---</span> <span class="o">---</span> <span class="o">---</span> <span class="o">---</span> <span class="o">---</span> <span class="o">----</span>
|
||
<span class="n">Total</span> <span class="mi">363</span> <span class="mi">286</span> <span class="mi">202</span> <span class="mi">73</span> <span class="mi">149</span> <span class="mi">230</span> <span class="mi">1303</span>
|
||
<span class="n">RejectAll</span> <span class="mi">82</span> <span class="mi">82</span> <span class="mi">82</span> <span class="mi">246</span>
|
||
<span class="o">---</span> <span class="o">---</span> <span class="o">---</span> <span class="o">---</span> <span class="o">---</span> <span class="o">---</span> <span class="o">----</span>
|
||
<span class="n">Total</span> <span class="mi">363</span> <span class="mi">286</span> <span class="mi">202</span> <span class="mi">155</span> <span class="mi">231</span> <span class="mi">312</span> <span class="mi">1549</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="choice-key">
|
||
<h3><a class="toc-backref" href="#choice-key" role="doc-backlink">CHOICE KEY</a></h3>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>A. x if C else y
|
||
B. if C then x else y
|
||
C. (if C: x else: y)
|
||
D. C ? x : y
|
||
E. C ? x ! y
|
||
F. cond(C, x, y)
|
||
G. C ?? x || y
|
||
H. C then x else y
|
||
I. x when C else y
|
||
J. C ? x else y
|
||
K. C -> x else y
|
||
L. C -> (x, y)
|
||
M. [x if C else y]
|
||
N. ifelse C: x else y
|
||
O. <if C then x else y>
|
||
P. C and x else y
|
||
Q. any write-in vote
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="detail-for-write-in-votes-and-their-ranking">
|
||
<h3><a class="toc-backref" href="#detail-for-write-in-votes-and-their-ranking" role="doc-backlink">Detail for write-in votes and their ranking</a></h3>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>3: Q reject y x C elsethenif
|
||
2: Q accept (C ? x ! y)
|
||
3: Q reject ...
|
||
3: Q accept ? C : x : y
|
||
3: Q accept (x if C, y otherwise)
|
||
3: Q reject ...
|
||
3: Q reject NONE
|
||
1: Q accept select : (<c1> : <val1>; [<cx> : <valx>; ]* elseval)
|
||
2: Q reject if C: t else: f
|
||
3: Q accept C selects x else y
|
||
2: Q accept iff(C, x, y) # "if-function"
|
||
1: Q accept (y, x)[C]
|
||
1: Q accept C true: x false: y
|
||
3: Q accept C then: x else: y
|
||
3: Q reject
|
||
3: Q accept (if C: x elif C2: y else: z)
|
||
3: Q accept C -> x : y
|
||
1: Q accept x (if C), y
|
||
1: Q accept if c: x else: y
|
||
3: Q accept (c).{True:1, False:2}
|
||
2: Q accept if c: x else: y
|
||
3: Q accept (c).{True:1, False:2}
|
||
3: Q accept if C: x else y
|
||
1: Q accept (x if C else y)
|
||
1: Q accept ifelse(C, x, y)
|
||
2: Q reject x or y <- C
|
||
1: Q accept (C ? x : y) required parens
|
||
1: Q accept iif(C, x, y)
|
||
1: Q accept ?(C, x, y)
|
||
1: Q accept switch-case
|
||
2: Q accept multi-line if/else
|
||
1: Q accept C: x else: y
|
||
2: Q accept (C): x else: y
|
||
3: Q accept if C: x else: y
|
||
1: Q accept x if C, else y
|
||
1: Q reject choice: c1->a; c2->b; ...; z
|
||
3: Q accept [if C then x else y]
|
||
3: Q reject no other choice has x as the first element
|
||
1: Q accept (x,y) ? C
|
||
3: Q accept x if C else y (The "else y" being optional)
|
||
1: Q accept (C ? x , y)
|
||
1: Q accept any outcome (i.e form or plain rejection) from a usability study
|
||
1: Q reject (x if C else y)
|
||
1: Q accept (x if C else y)
|
||
2: Q reject NONE
|
||
3: Q reject NONE
|
||
3: Q accept (C ? x else y)
|
||
3: Q accept x when C else y
|
||
2: Q accept (x if C else y)
|
||
2: Q accept cond(C1, x1, C2, x2, C3, x3,...)
|
||
1: Q accept (if C1: x elif C2: y else: z)
|
||
1: Q reject cond(C, :x, :y)
|
||
3: Q accept (C and [x] or [y])[0]
|
||
2: Q reject
|
||
3: Q reject
|
||
3: Q reject all else
|
||
1: Q reject no-change
|
||
3: Q reject deliberately omitted as I have no interest in any other proposal
|
||
2: Q reject (C then x else Y)
|
||
1: Q accept if C: x else: y
|
||
1: Q reject (if C then x else y)
|
||
3: Q reject C?(x, y)
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</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-0308.rst">https://github.com/python/peps/blob/main/peps/pep-0308.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0308.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="#adding-a-conditional-expression">Adding a conditional expression</a></li>
|
||
<li><a class="reference internal" href="#references">References</a></li>
|
||
<li><a class="reference internal" href="#introduction-to-earlier-draft-of-the-pep-kept-for-historical-purposes">Introduction to earlier draft of the PEP (kept for historical purposes)</a></li>
|
||
<li><a class="reference internal" href="#proposal">Proposal</a></li>
|
||
<li><a class="reference internal" href="#alternatives">Alternatives</a></li>
|
||
<li><a class="reference internal" href="#summary-of-the-current-state-of-the-discussion">Summary of the Current State of the Discussion</a></li>
|
||
<li><a class="reference internal" href="#short-circuit-behavior">Short-Circuit Behavior</a></li>
|
||
<li><a class="reference internal" href="#detailed-results-of-voting">Detailed Results of Voting</a><ul>
|
||
<li><a class="reference internal" href="#choice-key">CHOICE KEY</a></li>
|
||
<li><a class="reference internal" href="#detail-for-write-in-votes-and-their-ranking">Detail for write-in votes and their ranking</a></li>
|
||
</ul>
|
||
</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-0308.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> |