CINXE.COM
PEP 505 – None-aware operators | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 505 – None-aware operators | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0505/"> <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 505 – None-aware operators | peps.python.org'> <meta property="og:description" content="Several modern programming languages have so-called “null-coalescing” or “null- aware” operators, including C# 1, Dart 2, Perl, Swift, and PHP (starting in version 7). There are also stage 3 draft proposals for their addition to ECMAScript (a.k.a. JavaS..."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0505/"> <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="Several modern programming languages have so-called “null-coalescing” or “null- aware” operators, including C# 1, Dart 2, Perl, Swift, and PHP (starting in version 7). There are also stage 3 draft proposals for their addition to ECMAScript (a.k.a. JavaS..."> <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 505</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 505 – None-aware operators</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Mark E. Haase <mehaase at gmail.com>, Steve Dower <steve.dower at python.org></dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Inactive draft that may be taken up again at a later time">Deferred</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">18-Sep-2015</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">3.8</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="#syntax-and-semantics">Syntax and Semantics</a><ul> <li><a class="reference internal" href="#specialness-of-none">Specialness of <code class="docutils literal notranslate"><span class="pre">None</span></code></a></li> <li><a class="reference internal" href="#grammar-changes">Grammar changes</a><ul> <li><a class="reference internal" href="#the-coalesce-rule">The coalesce rule</a></li> <li><a class="reference internal" href="#the-maybe-dot-and-maybe-subscript-operators">The maybe-dot and maybe-subscript operators</a></li> </ul> </li> <li><a class="reference internal" href="#reading-expressions">Reading expressions</a></li> </ul> </li> <li><a class="reference internal" href="#examples">Examples</a><ul> <li><a class="reference internal" href="#standard-library">Standard Library</a></li> <li><a class="reference internal" href="#jsonify">jsonify</a></li> <li><a class="reference internal" href="#grab">Grab</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#no-value-protocol">No-Value Protocol</a></li> <li><a class="reference internal" href="#boolean-aware-operators">Boolean-aware operators</a></li> <li><a class="reference internal" href="#exception-aware-operators">Exception-aware operators</a></li> <li><a class="reference internal" href="#none-aware-function-call"><code class="docutils literal notranslate"><span class="pre">None</span></code>-aware Function Call</a></li> <li><a class="reference internal" href="#unary-postfix-operator"><code class="docutils literal notranslate"><span class="pre">?</span></code> Unary Postfix Operator</a></li> <li><a class="reference internal" href="#built-in-maybe">Built-in <code class="docutils literal notranslate"><span class="pre">maybe</span></code></a></li> <li><a class="reference internal" href="#just-use-a-conditional-expression">Just use a conditional expression</a></li> </ul> </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>Several modern programming languages have so-called “<code class="docutils literal notranslate"><span class="pre">null</span></code>-coalescing” or “<code class="docutils literal notranslate"><span class="pre">null</span></code>- aware” operators, including C# <a class="footnote-reference brackets" href="#id7" id="id1">[1]</a>, Dart <a class="footnote-reference brackets" href="#id8" id="id2">[2]</a>, Perl, Swift, and PHP (starting in version 7). There are also stage 3 draft proposals for their addition to ECMAScript (a.k.a. JavaScript) <a class="footnote-reference brackets" href="#id9" id="id3">[3]</a> <a class="footnote-reference brackets" href="#id10" id="id4">[4]</a>. These operators provide syntactic sugar for common patterns involving null references.</p> <ul class="simple"> <li>The “<code class="docutils literal notranslate"><span class="pre">null</span></code>-coalescing” operator is a binary operator that returns its left operand if it is not <code class="docutils literal notranslate"><span class="pre">null</span></code>. Otherwise it returns its right operand.</li> <li>The “<code class="docutils literal notranslate"><span class="pre">null</span></code>-aware member access” operator accesses an instance member only if that instance is non-<code class="docutils literal notranslate"><span class="pre">null</span></code>. Otherwise it returns <code class="docutils literal notranslate"><span class="pre">null</span></code>. (This is also called a “safe navigation” operator.)</li> <li>The “<code class="docutils literal notranslate"><span class="pre">null</span></code>-aware index access” operator accesses an element of a collection only if that collection is non-<code class="docutils literal notranslate"><span class="pre">null</span></code>. Otherwise it returns <code class="docutils literal notranslate"><span class="pre">null</span></code>. (This is another type of “safe navigation” operator.)</li> </ul> <p>This PEP proposes three <code class="docutils literal notranslate"><span class="pre">None</span></code>-aware operators for Python, based on the definitions and other language’s implementations of those above. Specifically:</p> <ul class="simple"> <li>The “<code class="docutils literal notranslate"><span class="pre">None</span></code> coalescing” binary operator <code class="docutils literal notranslate"><span class="pre">??</span></code> returns the left hand side if it evaluates to a value that is not <code class="docutils literal notranslate"><span class="pre">None</span></code>, or else it evaluates and returns the right hand side. A coalescing <code class="docutils literal notranslate"><span class="pre">??=</span></code> augmented assignment operator is included.</li> <li>The “<code class="docutils literal notranslate"><span class="pre">None</span></code>-aware attribute access” operator <code class="docutils literal notranslate"><span class="pre">?.</span></code> (“maybe dot”) evaluates the complete expression if the left hand side evaluates to a value that is not <code class="docutils literal notranslate"><span class="pre">None</span></code></li> <li>The “<code class="docutils literal notranslate"><span class="pre">None</span></code>-aware indexing” operator <code class="docutils literal notranslate"><span class="pre">?[]</span></code> (“maybe subscript”) evaluates the complete expression if the left hand site evaluates to a value that is not <code class="docutils literal notranslate"><span class="pre">None</span></code></li> </ul> <p>See the <a class="reference internal" href="#grammar-changes">Grammar changes</a> section for specifics and examples of the required grammar changes.</p> <p>See the <a class="reference internal" href="#examples">Examples</a> section for more realistic examples of code that could be updated to use the new operators.</p> </section> <section id="syntax-and-semantics"> <h2><a class="toc-backref" href="#syntax-and-semantics" role="doc-backlink">Syntax and Semantics</a></h2> <section id="specialness-of-none"> <h3><a class="toc-backref" href="#specialness-of-none" role="doc-backlink">Specialness of <code class="docutils literal notranslate"><span class="pre">None</span></code></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">None</span></code> object denotes the lack of a value. For the purposes of these operators, the lack of a value indicates that the remainder of the expression also lacks a value and should not be evaluated.</p> <p>A rejected proposal was to treat any value that evaluates as “false” in a Boolean context as not having a value. However, the purpose of these operators is to propagate the “lack of value” state, rather than the “false” state.</p> <p>Some argue that this makes <code class="docutils literal notranslate"><span class="pre">None</span></code> special. We contend that <code class="docutils literal notranslate"><span class="pre">None</span></code> is already special, and that using it as both the test and the result of these operators does not change the existing semantics in any way.</p> <p>See the <a class="reference internal" href="#rejected-ideas">Rejected Ideas</a> section for discussions on alternate approaches.</p> </section> <section id="grammar-changes"> <h3><a class="toc-backref" href="#grammar-changes" role="doc-backlink">Grammar changes</a></h3> <p>The following rules of the Python grammar are updated to read:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">augassign</span><span class="p">:</span> <span class="p">(</span><span class="s1">'+='</span> <span class="o">|</span> <span class="s1">'-='</span> <span class="o">|</span> <span class="s1">'*='</span> <span class="o">|</span> <span class="s1">'@='</span> <span class="o">|</span> <span class="s1">'/='</span> <span class="o">|</span> <span class="s1">'%='</span> <span class="o">|</span> <span class="s1">'&='</span> <span class="o">|</span> <span class="s1">'|='</span> <span class="o">|</span> <span class="s1">'^='</span> <span class="o">|</span> <span class="s1">'<<='</span> <span class="o">|</span> <span class="s1">'>>='</span> <span class="o">|</span> <span class="s1">'**='</span> <span class="o">|</span> <span class="s1">'//='</span> <span class="o">|</span> <span class="s1">'??='</span><span class="p">)</span> <span class="n">power</span><span class="p">:</span> <span class="n">coalesce</span> <span class="p">[</span><span class="s1">'**'</span> <span class="n">factor</span><span class="p">]</span> <span class="n">coalesce</span><span class="p">:</span> <span class="n">atom_expr</span> <span class="p">[</span><span class="s1">'??'</span> <span class="n">factor</span><span class="p">]</span> <span class="n">atom_expr</span><span class="p">:</span> <span class="p">[</span><span class="s1">'await'</span><span class="p">]</span> <span class="n">atom</span> <span class="n">trailer</span><span class="o">*</span> <span class="n">trailer</span><span class="p">:</span> <span class="p">(</span><span class="s1">'('</span> <span class="p">[</span><span class="n">arglist</span><span class="p">]</span> <span class="s1">')'</span> <span class="o">|</span> <span class="s1">'['</span> <span class="n">subscriptlist</span> <span class="s1">']'</span> <span class="o">|</span> <span class="s1">'?['</span> <span class="n">subscriptlist</span> <span class="s1">']'</span> <span class="o">|</span> <span class="s1">'.'</span> <span class="n">NAME</span> <span class="o">|</span> <span class="s1">'?.'</span> <span class="n">NAME</span><span class="p">)</span> </pre></div> </div> <section id="the-coalesce-rule"> <h4><a class="toc-backref" href="#the-coalesce-rule" role="doc-backlink">The coalesce rule</a></h4> <p>The <code class="docutils literal notranslate"><span class="pre">coalesce</span></code> rule provides the <code class="docutils literal notranslate"><span class="pre">??</span></code> binary operator. Unlike most binary operators, the right-hand side is not evaluated until the left-hand side is determined to be <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p> <p>The <code class="docutils literal notranslate"><span class="pre">??</span></code> operator binds more tightly than other binary operators as most existing implementations of these do not propagate <code class="docutils literal notranslate"><span class="pre">None</span></code> values (they will typically raise <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>). Expressions that are known to potentially result in <code class="docutils literal notranslate"><span class="pre">None</span></code> can be substituted for a default value without needing additional parentheses.</p> <p>Some examples of how implicit parentheses are placed when evaluating operator precedence in the presence of the <code class="docutils literal notranslate"><span class="pre">??</span></code> operator:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>a, b = None, None def c(): return None def ex(): raise Exception() (a ?? 2 ** b ?? 3) == a ?? (2 ** (b ?? 3)) (a * b ?? c // d) == a * (b ?? c) // d (a ?? True and b ?? False) == (a ?? True) and (b ?? False) (c() ?? c() ?? True) == True (True ?? ex()) == True (c ?? ex)() == c() </pre></div> </div> <p>Particularly for cases such as <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">??</span> <span class="pre">2</span> <span class="pre">**</span> <span class="pre">b</span> <span class="pre">??</span> <span class="pre">3</span></code>, parenthesizing the sub-expressions any other way would result in <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>, as <code class="docutils literal notranslate"><span class="pre">int.__pow__</span></code> cannot be called with <code class="docutils literal notranslate"><span class="pre">None</span></code> (and the fact that the <code class="docutils literal notranslate"><span class="pre">??</span></code> operator is used at all implies that <code class="docutils literal notranslate"><span class="pre">a</span></code> or <code class="docutils literal notranslate"><span class="pre">b</span></code> may be <code class="docutils literal notranslate"><span class="pre">None</span></code>). However, as usual, while parentheses are not required they should be added if it helps improve readability.</p> <p>An augmented assignment for the <code class="docutils literal notranslate"><span class="pre">??</span></code> operator is also added. Augmented coalescing assignment only rebinds the name if its current value is <code class="docutils literal notranslate"><span class="pre">None</span></code>. If the target name already has a value, the right-hand side is not evaluated. For example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>a = None b = '' c = 0 a ??= 'value' b ??= undefined_name c ??= shutil.rmtree('/') # don't try this at home, kids assert a == 'value' assert b == '' assert c == 0 and any(os.scandir('/')) </pre></div> </div> </section> <section id="the-maybe-dot-and-maybe-subscript-operators"> <h4><a class="toc-backref" href="#the-maybe-dot-and-maybe-subscript-operators" role="doc-backlink">The maybe-dot and maybe-subscript operators</a></h4> <p>The maybe-dot and maybe-subscript operators are added as trailers for atoms, so that they may be used in all the same locations as the regular operators, including as part of an assignment target (more details below). As the existing evaluation rules are not directly embedded in the grammar, we specify the required changes below.</p> <p>Assume that the <code class="docutils literal notranslate"><span class="pre">atom</span></code> is always successfully evaluated. Each <code class="docutils literal notranslate"><span class="pre">trailer</span></code> is then evaluated from left to right, applying its own parameter (either its arguments, subscripts or attribute name) to produce the value for the next <code class="docutils literal notranslate"><span class="pre">trailer</span></code>. Finally, if present, <code class="docutils literal notranslate"><span class="pre">await</span></code> is applied.</p> <p>For example, <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">a.b(c).d[e]</span></code> is currently parsed as <code class="docutils literal notranslate"><span class="pre">['await',</span> <span class="pre">'a',</span> <span class="pre">'.b',</span> <span class="pre">'(c)',</span> <span class="pre">'.d',</span> <span class="pre">'[e]']</span></code> and evaluated:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_v</span> <span class="o">=</span> <span class="n">a</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">b</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">d</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="p">[</span><span class="n">e</span><span class="p">]</span> <span class="k">await</span> <span class="n">_v</span> </pre></div> </div> <p>When a <code class="docutils literal notranslate"><span class="pre">None</span></code>-aware operator is present, the left-to-right evaluation may be short-circuited. For example, <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">a?.b(c).d?[e]</span></code> is evaluated:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_v</span> <span class="o">=</span> <span class="n">a</span> <span class="k">if</span> <span class="n">_v</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">b</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">d</span> <span class="k">if</span> <span class="n">_v</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="p">[</span><span class="n">e</span><span class="p">]</span> <span class="k">await</span> <span class="n">_v</span> </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p><code class="docutils literal notranslate"><span class="pre">await</span></code> will almost certainly fail in this context, as it would in the case where code attempts <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">None</span></code>. We are not proposing to add a <code class="docutils literal notranslate"><span class="pre">None</span></code>-aware <code class="docutils literal notranslate"><span class="pre">await</span></code> keyword here, and merely include it in this example for completeness of the specification, since the <code class="docutils literal notranslate"><span class="pre">atom_expr</span></code> grammar rule includes the keyword. If it were in its own rule, we would have never mentioned it.</p> </div> <p>Parenthesised expressions are handled by the <code class="docutils literal notranslate"><span class="pre">atom</span></code> rule (not shown above), which will implicitly terminate the short-circuiting behaviour of the above transformation. For example, <code class="docutils literal notranslate"><span class="pre">(a?.b</span> <span class="pre">??</span> <span class="pre">c).d?.e</span></code> is evaluated as:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># a?.b</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">a</span> <span class="k">if</span> <span class="n">_v</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">b</span> <span class="c1"># ... ?? c</span> <span class="k">if</span> <span class="n">_v</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">c</span> <span class="c1"># (...).d?.e</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">d</span> <span class="k">if</span> <span class="n">_v</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">e</span> </pre></div> </div> <p>When used as an assignment target, the <code class="docutils literal notranslate"><span class="pre">None</span></code>-aware operations may only be used in a “load” context. That is, <code class="docutils literal notranslate"><span class="pre">a?.b</span> <span class="pre">=</span> <span class="pre">1</span></code> and <code class="docutils literal notranslate"><span class="pre">a?[b]</span> <span class="pre">=</span> <span class="pre">1</span></code> will raise <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code>. Use earlier in the expression (<code class="docutils literal notranslate"><span class="pre">a?.b.c</span> <span class="pre">=</span> <span class="pre">1</span></code>) is permitted, though unlikely to be useful unless combined with a coalescing operation:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>(a?.b ?? d).c = 1 </pre></div> </div> </section> </section> <section id="reading-expressions"> <h3><a class="toc-backref" href="#reading-expressions" role="doc-backlink">Reading expressions</a></h3> <p>For the maybe-dot and maybe-subscript operators, the intention is that expressions including these operators should be read and interpreted as for the regular versions of these operators. In “normal” cases, the end results are going to be identical between an expression such as <code class="docutils literal notranslate"><span class="pre">a?.b?[c]</span></code> and <code class="docutils literal notranslate"><span class="pre">a.b[c]</span></code>, and just as we do not currently read “a.b” as “read attribute b from a <em>if it has an attribute a or else it raises AttributeError</em>”, there is no need to read “a?.b” as “read attribute b from a <em>if a is not None</em>” (unless in a context where the listener needs to be aware of the specific behaviour).</p> <p>For coalescing expressions using the <code class="docutils literal notranslate"><span class="pre">??</span></code> operator, expressions should either be read as “or … if None” or “coalesced with”. For example, the expression <code class="docutils literal notranslate"><span class="pre">a.get_value()</span> <span class="pre">??</span> <span class="pre">100</span></code> would be read “call a dot get_value or 100 if None”, or “call a dot get_value coalesced with 100”.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Reading code in spoken text is always lossy, and so we make no attempt to define an unambiguous way of speaking these operators. These suggestions are intended to add context to the implications of adding the new syntax.</p> </div> </section> </section> <section id="examples"> <h2><a class="toc-backref" href="#examples" role="doc-backlink">Examples</a></h2> <p>This section presents some examples of common <code class="docutils literal notranslate"><span class="pre">None</span></code> patterns and shows what conversion to use <code class="docutils literal notranslate"><span class="pre">None</span></code>-aware operators may look like.</p> <section id="standard-library"> <h3><a class="toc-backref" href="#standard-library" role="doc-backlink">Standard Library</a></h3> <p>Using the <code class="docutils literal notranslate"><span class="pre">find-pep505.py</span></code> script <a class="footnote-reference brackets" href="#id11" id="id5">[5]</a> an analysis of the Python 3.7 standard library discovered up to 678 code snippets that could be replaced with use of one of the <code class="docutils literal notranslate"><span class="pre">None</span></code>-aware operators:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ find /usr/lib/python3.7 -name '*.py' | xargs python3.7 find-pep505.py <snip> Total None-coalescing `if` blocks: 449 Total [possible] None-coalescing `or`: 120 Total None-coalescing ternaries: 27 Total Safe navigation `and`: 13 Total Safe navigation `if` blocks: 61 Total Safe navigation ternaries: 8 </pre></div> </div> <p>Some of these are shown below as examples before and after converting to use the new operators.</p> <p>From <code class="docutils literal notranslate"><span class="pre">bisect.py</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">insort_right</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">lo</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">hi</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="c1"># ...</span> <span class="k">if</span> <span class="n">hi</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">hi</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="c1"># ...</span> </pre></div> </div> <p>After updating to use the <code class="docutils literal notranslate"><span class="pre">??=</span></code> augmented assignment statement:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>def insort_right(a, x, lo=0, hi=None): # ... hi ??= len(a) # ... </pre></div> </div> <p>From <code class="docutils literal notranslate"><span class="pre">calendar.py</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">encoding</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">encoding</span> <span class="k">if</span> <span class="n">encoding</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">encoding</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">getdefaultencoding</span><span class="p">()</span> <span class="n">optdict</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">encoding</span><span class="o">=</span><span class="n">encoding</span><span class="p">,</span> <span class="n">css</span><span class="o">=</span><span class="n">options</span><span class="o">.</span><span class="n">css</span><span class="p">)</span> </pre></div> </div> <p>After updating to use the <code class="docutils literal notranslate"><span class="pre">??</span></code> operator:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>optdict = dict(encoding=options.encoding ?? sys.getdefaultencoding(), css=options.css) </pre></div> </div> <p>From <code class="docutils literal notranslate"><span class="pre">email/generator.py</span></code> (and importantly note that there is no way to substitute <code class="docutils literal notranslate"><span class="pre">or</span></code> for <code class="docutils literal notranslate"><span class="pre">??</span></code> in this situation):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">mangle_from_</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">policy</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">policy</span><span class="o">.</span><span class="n">mangle_from_</span> </pre></div> </div> <p>After updating:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>mangle_from_ = policy?.mangle_from_ ?? True </pre></div> </div> <p>From <code class="docutils literal notranslate"><span class="pre">asyncio/subprocess.py</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">pipe_data_received</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fd</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span> <span class="k">if</span> <span class="n">fd</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span> <span class="n">reader</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">stdout</span> <span class="k">elif</span> <span class="n">fd</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span> <span class="n">reader</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">stderr</span> <span class="k">else</span><span class="p">:</span> <span class="n">reader</span> <span class="o">=</span> <span class="kc">None</span> <span class="k">if</span> <span class="n">reader</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="n">reader</span><span class="o">.</span><span class="n">feed_data</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> </pre></div> </div> <p>After updating to use the <code class="docutils literal notranslate"><span class="pre">?.</span></code> operator:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>def pipe_data_received(self, fd, data): if fd == 1: reader = self.stdout elif fd == 2: reader = self.stderr else: reader = None reader?.feed_data(data) </pre></div> </div> <p>From <code class="docutils literal notranslate"><span class="pre">asyncio/tasks.py</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span> <span class="k">await</span> <span class="n">waiter</span> <span class="k">finally</span><span class="p">:</span> <span class="k">if</span> <span class="n">timeout_handle</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="n">timeout_handle</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span> </pre></div> </div> <p>After updating to use the <code class="docutils literal notranslate"><span class="pre">?.</span></code> operator:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>try: await waiter finally: timeout_handle?.cancel() </pre></div> </div> <p>From <code class="docutils literal notranslate"><span class="pre">ctypes/_aix.py</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">libpaths</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">libpaths</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">else</span><span class="p">:</span> <span class="n">libpaths</span> <span class="o">=</span> <span class="n">libpaths</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">":"</span><span class="p">)</span> </pre></div> </div> <p>After updating:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>libpaths = libpaths?.split(":") ?? [] </pre></div> </div> <p>From <code class="docutils literal notranslate"><span class="pre">os.py</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">entry</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span> <span class="n">dirs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="k">if</span> <span class="n">entries</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="n">entries</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">entry</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">nondirs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> </pre></div> </div> <p>After updating to use the <code class="docutils literal notranslate"><span class="pre">?.</span></code> operator:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if entry.is_dir(): dirs.append(name) entries?.append(entry) else: nondirs.append(name) </pre></div> </div> <p>From <code class="docutils literal notranslate"><span class="pre">importlib/abc.py</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">find_module</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">):</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s1">'find_spec'</span><span class="p">):</span> <span class="k">return</span> <span class="kc">None</span> <span class="n">found</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">find_spec</span><span class="p">(</span><span class="n">fullname</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span> <span class="k">return</span> <span class="n">found</span><span class="o">.</span><span class="n">loader</span> <span class="k">if</span> <span class="n">found</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="kc">None</span> </pre></div> </div> <p>After partially updating:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>def find_module(self, fullname, path): if not hasattr(self, 'find_spec'): return None return self.find_spec(fullname, path)?.loader </pre></div> </div> <p>After extensive updating (arguably excessive, though that’s for the style guides to determine):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>def find_module(self, fullname, path): return getattr(self, 'find_spec', None)?.__call__(fullname, path)?.loader </pre></div> </div> <p>From <code class="docutils literal notranslate"><span class="pre">dis.py</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">_get_const_info</span><span class="p">(</span><span class="n">const_index</span><span class="p">,</span> <span class="n">const_list</span><span class="p">):</span> <span class="n">argval</span> <span class="o">=</span> <span class="n">const_index</span> <span class="k">if</span> <span class="n">const_list</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="n">argval</span> <span class="o">=</span> <span class="n">const_list</span><span class="p">[</span><span class="n">const_index</span><span class="p">]</span> <span class="k">return</span> <span class="n">argval</span><span class="p">,</span> <span class="nb">repr</span><span class="p">(</span><span class="n">argval</span><span class="p">)</span> </pre></div> </div> <p>After updating to use the <code class="docutils literal notranslate"><span class="pre">?[]</span></code> and <code class="docutils literal notranslate"><span class="pre">??</span></code> operators:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>def _get_const_info(const_index, const_list): argval = const_list?[const_index] ?? const_index return argval, repr(argval) </pre></div> </div> </section> <section id="jsonify"> <h3><a class="toc-backref" href="#jsonify" role="doc-backlink">jsonify</a></h3> <p>This example is from a Python web crawler that uses the Flask framework as its front-end. This function retrieves information about a web site from a SQL database and formats it as JSON to send to an HTTP client:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">SiteView</span><span class="p">(</span><span class="n">FlaskView</span><span class="p">):</span> <span class="nd">@route</span><span class="p">(</span><span class="s1">'/site/<id_>'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'GET'</span><span class="p">])</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_site</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">id_</span><span class="p">):</span> <span class="n">site</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="s1">'site_table'</span><span class="p">)</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">id_</span><span class="p">)</span> <span class="k">return</span> <span class="n">jsonify</span><span class="p">(</span> <span class="n">first_seen</span><span class="o">=</span><span class="n">site</span><span class="o">.</span><span class="n">first_seen</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="k">if</span> <span class="n">site</span><span class="o">.</span><span class="n">first_seen</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="n">site</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="n">is_active</span><span class="o">=</span><span class="n">site</span><span class="o">.</span><span class="n">is_active</span><span class="p">,</span> <span class="n">last_seen</span><span class="o">=</span><span class="n">site</span><span class="o">.</span><span class="n">last_seen</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="k">if</span> <span class="n">site</span><span class="o">.</span><span class="n">last_seen</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span> <span class="n">url</span><span class="o">=</span><span class="n">site</span><span class="o">.</span><span class="n">url</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span> <span class="p">)</span> </pre></div> </div> <p>Both <code class="docutils literal notranslate"><span class="pre">first_seen</span></code> and <code class="docutils literal notranslate"><span class="pre">last_seen</span></code> are allowed to be <code class="docutils literal notranslate"><span class="pre">null</span></code> in the database, and they are also allowed to be <code class="docutils literal notranslate"><span class="pre">null</span></code> in the JSON response. JSON does not have a native way to represent a <code class="docutils literal notranslate"><span class="pre">datetime</span></code>, so the server’s contract states that any non-<code class="docutils literal notranslate"><span class="pre">null</span></code> date is represented as an ISO-8601 string.</p> <p>Without knowing the exact semantics of the <code class="docutils literal notranslate"><span class="pre">first_seen</span></code> and <code class="docutils literal notranslate"><span class="pre">last_seen</span></code> attributes, it is impossible to know whether the attribute can be safely or performantly accessed multiple times.</p> <p>One way to fix this code is to replace each conditional expression with an explicit value assignment and a full <code class="docutils literal notranslate"><span class="pre">if</span></code>/<code class="docutils literal notranslate"><span class="pre">else</span></code> block:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">SiteView</span><span class="p">(</span><span class="n">FlaskView</span><span class="p">):</span> <span class="nd">@route</span><span class="p">(</span><span class="s1">'/site/<id_>'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'GET'</span><span class="p">])</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_site</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">id_</span><span class="p">):</span> <span class="n">site</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="s1">'site_table'</span><span class="p">)</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">id_</span><span class="p">)</span> <span class="n">first_seen_dt</span> <span class="o">=</span> <span class="n">site</span><span class="o">.</span><span class="n">first_seen</span> <span class="k">if</span> <span class="n">first_seen_dt</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">first_seen</span> <span class="o">=</span> <span class="kc">None</span> <span class="k">else</span><span class="p">:</span> <span class="n">first_seen</span> <span class="o">=</span> <span class="n">first_seen_dt</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="n">last_seen_dt</span> <span class="o">=</span> <span class="n">site</span><span class="o">.</span><span class="n">last_seen</span> <span class="k">if</span> <span class="n">last_seen_dt</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">last_seen</span> <span class="o">=</span> <span class="kc">None</span> <span class="k">else</span><span class="p">:</span> <span class="n">last_seen</span> <span class="o">=</span> <span class="n">last_seen_dt</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="k">return</span> <span class="n">jsonify</span><span class="p">(</span> <span class="n">first_seen</span><span class="o">=</span><span class="n">first_seen</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="n">site</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="n">is_active</span><span class="o">=</span><span class="n">site</span><span class="o">.</span><span class="n">is_active</span><span class="p">,</span> <span class="n">last_seen</span><span class="o">=</span><span class="n">last_seen</span><span class="p">,</span> <span class="n">url</span><span class="o">=</span><span class="n">site</span><span class="o">.</span><span class="n">url</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span> <span class="p">)</span> </pre></div> </div> <p>This adds ten lines of code and four new code paths to the function, dramatically increasing the apparent complexity. Rewriting using the <code class="docutils literal notranslate"><span class="pre">None</span></code>-aware attribute operator results in shorter code with more clear intent:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>class SiteView(FlaskView): @route('/site/<id_>', methods=['GET']) def get_site(self, id_): site = db.query('site_table').find(id_) return jsonify( first_seen=site.first_seen?.isoformat(), id=site.id, is_active=site.is_active, last_seen=site.last_seen?.isoformat(), url=site.url.rstrip('/') ) </pre></div> </div> </section> <section id="grab"> <h3><a class="toc-backref" href="#grab" role="doc-backlink">Grab</a></h3> <p>The next example is from a Python scraping library called <a class="reference external" href="https://github.com/lorien/grab/blob/4c95b18dcb0fa88eeca81f5643c0ebfb114bf728/grab/upload.py">Grab</a>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">BaseUploadObject</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="nf">find_content_type</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="n">ctype</span><span class="p">,</span> <span class="n">encoding</span> <span class="o">=</span> <span class="n">mimetypes</span><span class="o">.</span><span class="n">guess_type</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">if</span> <span class="n">ctype</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="k">return</span> <span class="s1">'application/octet-stream'</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">ctype</span> <span class="k">class</span><span class="w"> </span><span class="nc">UploadContent</span><span class="p">(</span><span class="n">BaseUploadObject</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">content_type</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">content</span> <span class="o">=</span> <span class="n">content</span> <span class="k">if</span> <span class="n">filename</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filename</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_random_filename</span><span class="p">()</span> <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filename</span> <span class="o">=</span> <span class="n">filename</span> <span class="k">if</span> <span class="n">content_type</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">find_content_type</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="n">content_type</span> <span class="k">class</span><span class="w"> </span><span class="nc">UploadFile</span><span class="p">(</span><span class="n">BaseUploadObject</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">content_type</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">path</span> <span class="o">=</span> <span class="n">path</span> <span class="k">if</span> <span class="n">filename</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">path</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filename</span> <span class="o">=</span> <span class="n">filename</span> <span class="k">if</span> <span class="n">content_type</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">find_content_type</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="n">content_type</span> </pre></div> </div> <p>This example contains several good examples of needing to provide default values. Rewriting to use conditional expressions reduces the overall lines of code, but does not necessarily improve readability:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">BaseUploadObject</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="nf">find_content_type</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="n">ctype</span><span class="p">,</span> <span class="n">encoding</span> <span class="o">=</span> <span class="n">mimetypes</span><span class="o">.</span><span class="n">guess_type</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">return</span> <span class="s1">'application/octet-stream'</span> <span class="k">if</span> <span class="n">ctype</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">ctype</span> <span class="k">class</span><span class="w"> </span><span class="nc">UploadContent</span><span class="p">(</span><span class="n">BaseUploadObject</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">content_type</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">content</span> <span class="o">=</span> <span class="n">content</span> <span class="bp">self</span><span class="o">.</span><span class="n">filename</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_random_filename</span><span class="p">()</span> <span class="k">if</span> <span class="n">filename</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">filename</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">find_content_type</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span> <span class="k">if</span> <span class="n">content_type</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">content_type</span><span class="p">)</span> <span class="k">class</span><span class="w"> </span><span class="nc">UploadFile</span><span class="p">(</span><span class="n">BaseUploadObject</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">content_type</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">path</span> <span class="o">=</span> <span class="n">path</span> <span class="bp">self</span><span class="o">.</span><span class="n">filename</span> <span class="o">=</span> <span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">path</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">filename</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">filename</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">find_content_type</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span> <span class="k">if</span> <span class="n">content_type</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">content_type</span><span class="p">)</span> </pre></div> </div> <p>The first ternary expression is tidy, but it reverses the intuitive order of the operands: it should return <code class="docutils literal notranslate"><span class="pre">ctype</span></code> if it has a value and use the string literal as fallback. The other ternary expressions are unintuitive and so long that they must be wrapped. The overall readability is worsened, not improved.</p> <p>Rewriting using the <code class="docutils literal notranslate"><span class="pre">None</span></code> coalescing operator:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>class BaseUploadObject(object): def find_content_type(self, filename): ctype, encoding = mimetypes.guess_type(filename) return ctype ?? 'application/octet-stream' class UploadContent(BaseUploadObject): def __init__(self, content, filename=None, content_type=None): self.content = content self.filename = filename ?? self.get_random_filename() self.content_type = content_type ?? self.find_content_type(self.filename) class UploadFile(BaseUploadObject): def __init__(self, path, filename=None, content_type=None): self.path = path self.filename = filename ?? os.path.split(path)[1] self.content_type = content_type ?? self.find_content_type(self.filename) </pre></div> </div> <p>This syntax has an intuitive ordering of the operands. In <code class="docutils literal notranslate"><span class="pre">find_content_type</span></code>, for example, the preferred value <code class="docutils literal notranslate"><span class="pre">ctype</span></code> appears before the fallback value. The terseness of the syntax also makes for fewer lines of code and less code to visually parse, and reading from left-to-right and top-to-bottom more accurately follows the execution flow.</p> </section> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> <p>The first three ideas in this section are oft-proposed alternatives to treating <code class="docutils literal notranslate"><span class="pre">None</span></code> as special. For further background on why these are rejected, see their treatment in <a class="pep reference internal" href="../pep-0531/" title="PEP 531 – Existence checking operators">PEP 531</a> and <a class="pep reference internal" href="../pep-0532/" title="PEP 532 – A circuit breaking protocol and binary operators">PEP 532</a> and the associated discussions.</p> <section id="no-value-protocol"> <h3><a class="toc-backref" href="#no-value-protocol" role="doc-backlink">No-Value Protocol</a></h3> <p>The operators could be generalised to user-defined types by defining a protocol to indicate when a value represents “no value”. Such a protocol may be a dunder method <code class="docutils literal notranslate"><span class="pre">__has_value__(self)</span></code> that returns <code class="docutils literal notranslate"><span class="pre">True</span></code> if the value should be treated as having a value, and <code class="docutils literal notranslate"><span class="pre">False</span></code> if the value should be treated as no value.</p> <p>With this generalization, <code class="docutils literal notranslate"><span class="pre">object</span></code> would implement a dunder method equivalent to this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">__has_value__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="kc">True</span> </pre></div> </div> <p><code class="docutils literal notranslate"><span class="pre">NoneType</span></code> would implement a dunder method equivalent to this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">__has_value__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="kc">False</span> </pre></div> </div> <p>In the specification section, all uses of <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">is</span> <span class="pre">None</span></code> would be replaced with <code class="docutils literal notranslate"><span class="pre">not</span> <span class="pre">x.__has_value__()</span></code>.</p> <p>This generalization would allow for domain-specific “no-value” objects to be coalesced just like <code class="docutils literal notranslate"><span class="pre">None</span></code>. For example, the <code class="docutils literal notranslate"><span class="pre">pyasn1</span></code> package has a type called <code class="docutils literal notranslate"><span class="pre">Null</span></code> that represents an ASN.1 <code class="docutils literal notranslate"><span class="pre">null</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>>>> from pyasn1.type import univ >>> univ.Null() ?? univ.Integer(123) Integer(123) </pre></div> </div> <p>Similarly, values such as <code class="docutils literal notranslate"><span class="pre">math.nan</span></code> and <code class="docutils literal notranslate"><span class="pre">NotImplemented</span></code> could be treated as representing no value.</p> <p>However, the “no-value” nature of these values is domain-specific, which means they <em>should</em> be treated as a value by the language. For example, <code class="docutils literal notranslate"><span class="pre">math.nan.imag</span></code> is well defined (it’s <code class="docutils literal notranslate"><span class="pre">0.0</span></code>), and so short-circuiting <code class="docutils literal notranslate"><span class="pre">math.nan?.imag</span></code> to return <code class="docutils literal notranslate"><span class="pre">math.nan</span></code> would be incorrect.</p> <p>As <code class="docutils literal notranslate"><span class="pre">None</span></code> is already defined by the language as being the value that represents “no value”, and the current specification would not preclude switching to a protocol in the future (though changes to built-in objects would not be compatible), this idea is rejected for now.</p> </section> <section id="boolean-aware-operators"> <h3><a class="toc-backref" href="#boolean-aware-operators" role="doc-backlink">Boolean-aware operators</a></h3> <p>This suggestion is fundamentally the same as adding a no-value protocol, and so the discussion above also applies.</p> <p>Similar behavior to the <code class="docutils literal notranslate"><span class="pre">??</span></code> operator can be achieved with an <code class="docutils literal notranslate"><span class="pre">or</span></code> expression, however <code class="docutils literal notranslate"><span class="pre">or</span></code> checks whether its left operand is false-y and not specifically <code class="docutils literal notranslate"><span class="pre">None</span></code>. This approach is attractive, as it requires fewer changes to the language, but ultimately does not solve the underlying problem correctly.</p> <p>Assuming the check is for truthiness rather than <code class="docutils literal notranslate"><span class="pre">None</span></code>, there is no longer a need for the <code class="docutils literal notranslate"><span class="pre">??</span></code> operator. However, applying this check to the <code class="docutils literal notranslate"><span class="pre">?.</span></code> and <code class="docutils literal notranslate"><span class="pre">?[]</span></code> operators prevents perfectly valid operations applying</p> <p>Consider the following example, where <code class="docutils literal notranslate"><span class="pre">get_log_list()</span></code> may return either a list containing current log messages (potentially empty), or <code class="docutils literal notranslate"><span class="pre">None</span></code> if logging is not enabled:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>lst = get_log_list() lst?.append('A log message') </pre></div> </div> <p>If <code class="docutils literal notranslate"><span class="pre">?.</span></code> is checking for true values rather than specifically <code class="docutils literal notranslate"><span class="pre">None</span></code> and the log has not been initialized with any items, no item will ever be appended. This violates the obvious intent of the code, which is to append an item. The <code class="docutils literal notranslate"><span class="pre">append</span></code> method is available on an empty list, as are all other list methods, and there is no reason to assume that these members should not be used because the list is presently empty.</p> <p>Further, there is no sensible result to use in place of the expression. A normal <code class="docutils literal notranslate"><span class="pre">lst.append</span></code> returns <code class="docutils literal notranslate"><span class="pre">None</span></code>, but under this idea <code class="docutils literal notranslate"><span class="pre">lst?.append</span></code> may result in either <code class="docutils literal notranslate"><span class="pre">[]</span></code> or <code class="docutils literal notranslate"><span class="pre">None</span></code>, depending on the value of <code class="docutils literal notranslate"><span class="pre">lst</span></code>. As with the examples in the previous section, this makes no sense.</p> <p>As checking for truthiness rather than <code class="docutils literal notranslate"><span class="pre">None</span></code> results in apparently valid expressions no longer executing as intended, this idea is rejected.</p> </section> <section id="exception-aware-operators"> <h3><a class="toc-backref" href="#exception-aware-operators" role="doc-backlink">Exception-aware operators</a></h3> <p>Arguably, the reason to short-circuit an expression when <code class="docutils literal notranslate"><span class="pre">None</span></code> is encountered is to avoid the <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> or <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> that would be raised under normal circumstances. As an alternative to testing for <code class="docutils literal notranslate"><span class="pre">None</span></code>, the <code class="docutils literal notranslate"><span class="pre">?.</span></code> and <code class="docutils literal notranslate"><span class="pre">?[]</span></code> operators could instead handle <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> and <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> raised by the operation and skip the remainder of the expression.</p> <p>This produces a transformation for <code class="docutils literal notranslate"><span class="pre">a?.b.c?.d.e</span></code> similar to this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_v</span> <span class="o">=</span> <span class="n">a</span> <span class="k">try</span><span class="p">:</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">b</span> <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span> <span class="k">pass</span> <span class="k">else</span><span class="p">:</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">c</span> <span class="k">try</span><span class="p">:</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">d</span> <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span> <span class="k">pass</span> <span class="k">else</span><span class="p">:</span> <span class="n">_v</span> <span class="o">=</span> <span class="n">_v</span><span class="o">.</span><span class="n">e</span> </pre></div> </div> <p>One open question is which value should be returned as the expression when an exception is handled. The above example simply leaves the partial result, but this is not helpful for replacing with a default value. An alternative would be to force the result to <code class="docutils literal notranslate"><span class="pre">None</span></code>, which then raises the question as to why <code class="docutils literal notranslate"><span class="pre">None</span></code> is special enough to be the result but not special enough to be the test.</p> <p>Secondly, this approach masks errors within code executed implicitly as part of the expression. For <code class="docutils literal notranslate"><span class="pre">?.</span></code>, any <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> within a property or <code class="docutils literal notranslate"><span class="pre">__getattr__</span></code> implementation would be hidden, and similarly for <code class="docutils literal notranslate"><span class="pre">?[]</span></code> and <code class="docutils literal notranslate"><span class="pre">__getitem__</span></code> implementations.</p> <p>Similarly, simple typing errors such as <code class="docutils literal notranslate"><span class="pre">{}?.ietms()</span></code> could go unnoticed.</p> <p>Existing conventions for handling these kinds of errors in the form of the <code class="docutils literal notranslate"><span class="pre">getattr</span></code> builtin and the <code class="docutils literal notranslate"><span class="pre">.get(key,</span> <span class="pre">default)</span></code> method pattern established by <code class="docutils literal notranslate"><span class="pre">dict</span></code> show that it is already possible to explicitly use this behaviour.</p> <p>As this approach would hide errors in code, it is rejected.</p> </section> <section id="none-aware-function-call"> <h3><a class="toc-backref" href="#none-aware-function-call" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">None</span></code>-aware Function Call</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">None</span></code>-aware syntax applies to attribute and index access, so it seems natural to ask if it should also apply to function invocation syntax. It might be written as <code class="docutils literal notranslate"><span class="pre">foo?()</span></code>, where <code class="docutils literal notranslate"><span class="pre">foo</span></code> is only called if it is not None.</p> <p>This has been deferred on the basis of the proposed operators being intended to aid traversal of partially populated hierarchical data structures, <em>not</em> for traversal of arbitrary class hierarchies. This is reflected in the fact that none of the other mainstream languages that already offer this syntax have found it worthwhile to support a similar syntax for optional function invocations.</p> <p>A workaround similar to that used by C# would be to write <code class="docutils literal notranslate"><span class="pre">maybe_none?.__call__(arguments)</span></code>. If the callable is <code class="docutils literal notranslate"><span class="pre">None</span></code>, the expression will not be evaluated. (The C# equivalent uses <code class="docutils literal notranslate"><span class="pre">?.Invoke()</span></code> on its callable type.)</p> </section> <section id="unary-postfix-operator"> <h3><a class="toc-backref" href="#unary-postfix-operator" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">?</span></code> Unary Postfix Operator</a></h3> <p>To generalize the <code class="docutils literal notranslate"><span class="pre">None</span></code>-aware behavior and limit the number of new operators introduced, a unary, postfix operator spelled <code class="docutils literal notranslate"><span class="pre">?</span></code> was suggested. The idea is that <code class="docutils literal notranslate"><span class="pre">?</span></code> might return a special object that could would override dunder methods that return <code class="docutils literal notranslate"><span class="pre">self</span></code>. For example, <code class="docutils literal notranslate"><span class="pre">foo?</span></code> would evaluate to <code class="docutils literal notranslate"><span class="pre">foo</span></code> if it is not <code class="docutils literal notranslate"><span class="pre">None</span></code>, otherwise it would evaluate to an instance of <code class="docutils literal notranslate"><span class="pre">NoneQuestion</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">NoneQuestion</span><span class="p">():</span> <span class="k">def</span><span class="w"> </span><span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> <span class="k">return</span> <span class="bp">self</span> <span class="k">def</span><span class="w"> </span><span class="fm">__getattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span> <span class="k">return</span> <span class="bp">self</span> <span class="k">def</span><span class="w"> </span><span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span> <span class="k">return</span> <span class="bp">self</span> </pre></div> </div> <p>With this new operator and new type, an expression like <code class="docutils literal notranslate"><span class="pre">foo?.bar[baz]</span></code> evaluates to <code class="docutils literal notranslate"><span class="pre">NoneQuestion</span></code> if <code class="docutils literal notranslate"><span class="pre">foo</span></code> is None. This is a nifty generalization, but it’s difficult to use in practice since most existing code won’t know what <code class="docutils literal notranslate"><span class="pre">NoneQuestion</span></code> is.</p> <p>Going back to one of the motivating examples above, consider the following:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>>>> import json >>> created = None >>> json.dumps({'created': created?.isoformat()}) </pre></div> </div> <p>The JSON serializer does not know how to serialize <code class="docutils literal notranslate"><span class="pre">NoneQuestion</span></code>, nor will any other API. This proposal actually requires <em>lots of specialized logic</em> throughout the standard library and any third party library.</p> <p>At the same time, the <code class="docutils literal notranslate"><span class="pre">?</span></code> operator may also be <strong>too general</strong>, in the sense that it can be combined with any other operator. What should the following expressions mean?:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>>>> x? + 1 >>> x? -= 1 >>> x? == 1 >>> ~x? </pre></div> </div> <p>This degree of generalization is not useful. The operators actually proposed herein are intentionally limited to a few operators that are expected to make it easier to write common code patterns.</p> </section> <section id="built-in-maybe"> <h3><a class="toc-backref" href="#built-in-maybe" role="doc-backlink">Built-in <code class="docutils literal notranslate"><span class="pre">maybe</span></code></a></h3> <p>Haskell has a concept called <a class="reference external" href="https://wiki.haskell.org/Maybe">Maybe</a> that encapsulates the idea of an optional value without relying on any special keyword (e.g. <code class="docutils literal notranslate"><span class="pre">null</span></code>) or any special instance (e.g. <code class="docutils literal notranslate"><span class="pre">None</span></code>). In Haskell, the purpose of <code class="docutils literal notranslate"><span class="pre">Maybe</span></code> is to avoid separate handling of “something” and nothing”.</p> <p>A Python package called <a class="reference external" href="https://pypi.org/p/pymaybe/">pymaybe</a> provides a rough approximation. The documentation shows the following example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">maybe</span><span class="p">(</span><span class="s1">'VALUE'</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="go">'value'</span> <span class="gp">>>> </span><span class="n">maybe</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span><span class="o">.</span><span class="n">invalid</span><span class="p">()</span><span class="o">.</span><span class="n">method</span><span class="p">()</span><span class="o">.</span><span class="n">or_else</span><span class="p">(</span><span class="s1">'unknown'</span><span class="p">)</span> <span class="go">'unknown'</span> </pre></div> </div> <p>The function <code class="docutils literal notranslate"><span class="pre">maybe()</span></code> returns either a <code class="docutils literal notranslate"><span class="pre">Something</span></code> instance or a <code class="docutils literal notranslate"><span class="pre">Nothing</span></code> instance. Similar to the unary postfix operator described in the previous section, <code class="docutils literal notranslate"><span class="pre">Nothing</span></code> overrides dunder methods in order to allow chaining on a missing value.</p> <p>Note that <code class="docutils literal notranslate"><span class="pre">or_else()</span></code> is eventually required to retrieve the underlying value from <code class="docutils literal notranslate"><span class="pre">pymaybe</span></code>’s wrappers. Furthermore, <code class="docutils literal notranslate"><span class="pre">pymaybe</span></code> does not short circuit any evaluation. Although <code class="docutils literal notranslate"><span class="pre">pymaybe</span></code> has some strengths and may be useful in its own right, it also demonstrates why a pure Python implementation of coalescing is not nearly as powerful as support built into the language.</p> <p>The idea of adding a builtin <code class="docutils literal notranslate"><span class="pre">maybe</span></code> type to enable this scenario is rejected.</p> </section> <section id="just-use-a-conditional-expression"> <h3><a class="toc-backref" href="#just-use-a-conditional-expression" role="doc-backlink">Just use a conditional expression</a></h3> <p>Another common way to initialize default values is to use the ternary operator. Here is an excerpt from the popular <a class="reference external" href="https://github.com/kennethreitz/requests/blob/14a555ac716866678bf17e43e23230d81a8149f5/requests/models.py#L212">Requests package</a>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">data</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="n">data</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">data</span> <span class="n">files</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="n">files</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">files</span> <span class="n">headers</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">if</span> <span class="n">headers</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">headers</span> <span class="n">params</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">if</span> <span class="n">params</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">params</span> <span class="n">hooks</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">if</span> <span class="n">hooks</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">hooks</span> </pre></div> </div> <p>This particular formulation has the undesirable effect of putting the operands in an unintuitive order: the brain thinks, “use <code class="docutils literal notranslate"><span class="pre">data</span></code> if possible and use <code class="docutils literal notranslate"><span class="pre">[]</span></code> as a fallback,” but the code puts the fallback <em>before</em> the preferred value.</p> <p>The author of this package could have written it like this instead:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span> <span class="k">if</span> <span class="n">data</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="p">[]</span> <span class="n">files</span> <span class="o">=</span> <span class="n">files</span> <span class="k">if</span> <span class="n">files</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="p">[]</span> <span class="n">headers</span> <span class="o">=</span> <span class="n">headers</span> <span class="k">if</span> <span class="n">headers</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="p">{}</span> <span class="n">params</span> <span class="o">=</span> <span class="n">params</span> <span class="k">if</span> <span class="n">params</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="p">{}</span> <span class="n">hooks</span> <span class="o">=</span> <span class="n">hooks</span> <span class="k">if</span> <span class="n">hooks</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="p">{}</span> </pre></div> </div> <p>This ordering of the operands is more intuitive, but it requires 4 extra characters (for “not “). It also highlights the repetition of identifiers: <code class="docutils literal notranslate"><span class="pre">data</span> <span class="pre">if</span> <span class="pre">data</span></code>, <code class="docutils literal notranslate"><span class="pre">files</span> <span class="pre">if</span> <span class="pre">files</span></code>, etc.</p> <p>When written using the <code class="docutils literal notranslate"><span class="pre">None</span></code> coalescing operator, the sample reads:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>data = data ?? [] files = files ?? [] headers = headers ?? {} params = params ?? {} hooks = hooks ?? {} </pre></div> </div> </section> </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="id7" role="doc-footnote"> <dt class="label" id="id7">[<a href="#id1">1</a>]</dt> <dd>C# Reference: Operators (<a class="reference external" href="https://learn.microsoft.com/en/dotnet/csharp/language-reference/operators/">https://learn.microsoft.com/en/dotnet/csharp/language-reference/operators/</a>)</aside> <aside class="footnote brackets" id="id8" role="doc-footnote"> <dt class="label" id="id8">[<a href="#id2">2</a>]</dt> <dd>A Tour of the Dart Language: Operators (<a class="reference external" href="https://www.dartlang.org/docs/dart-up-and-running/ch02.html#operators">https://www.dartlang.org/docs/dart-up-and-running/ch02.html#operators</a>)</aside> <aside class="footnote brackets" id="id9" role="doc-footnote"> <dt class="label" id="id9">[<a href="#id3">3</a>]</dt> <dd>Proposal: Nullish Coalescing for JavaScript (<a class="reference external" href="https://github.com/tc39/proposal-nullish-coalescing">https://github.com/tc39/proposal-nullish-coalescing</a>)</aside> <aside class="footnote brackets" id="id10" role="doc-footnote"> <dt class="label" id="id10">[<a href="#id4">4</a>]</dt> <dd>Proposal: Optional Chaining for JavaScript (<a class="reference external" href="https://github.com/tc39/proposal-optional-chaining">https://github.com/tc39/proposal-optional-chaining</a>)</aside> <aside class="footnote brackets" id="id11" role="doc-footnote"> <dt class="label" id="id11">[<a href="#id5">5</a>]</dt> <dd>Associated scripts (<a class="reference external" href="https://github.com/python/peps/tree/master/pep-0505/">https://github.com/python/peps/tree/master/pep-0505/</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-0505.rst">https://github.com/python/peps/blob/main/peps/pep-0505.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0505.rst">2025-02-01 08:55:40 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#syntax-and-semantics">Syntax and Semantics</a><ul> <li><a class="reference internal" href="#specialness-of-none">Specialness of <code class="docutils literal notranslate"><span class="pre">None</span></code></a></li> <li><a class="reference internal" href="#grammar-changes">Grammar changes</a><ul> <li><a class="reference internal" href="#the-coalesce-rule">The coalesce rule</a></li> <li><a class="reference internal" href="#the-maybe-dot-and-maybe-subscript-operators">The maybe-dot and maybe-subscript operators</a></li> </ul> </li> <li><a class="reference internal" href="#reading-expressions">Reading expressions</a></li> </ul> </li> <li><a class="reference internal" href="#examples">Examples</a><ul> <li><a class="reference internal" href="#standard-library">Standard Library</a></li> <li><a class="reference internal" href="#jsonify">jsonify</a></li> <li><a class="reference internal" href="#grab">Grab</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#no-value-protocol">No-Value Protocol</a></li> <li><a class="reference internal" href="#boolean-aware-operators">Boolean-aware operators</a></li> <li><a class="reference internal" href="#exception-aware-operators">Exception-aware operators</a></li> <li><a class="reference internal" href="#none-aware-function-call"><code class="docutils literal notranslate"><span class="pre">None</span></code>-aware Function Call</a></li> <li><a class="reference internal" href="#unary-postfix-operator"><code class="docutils literal notranslate"><span class="pre">?</span></code> Unary Postfix Operator</a></li> <li><a class="reference internal" href="#built-in-maybe">Built-in <code class="docutils literal notranslate"><span class="pre">maybe</span></code></a></li> <li><a class="reference internal" href="#just-use-a-conditional-expression">Just use a conditional expression</a></li> </ul> </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-0505.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>