CINXE.COM
PEP 584 – Add Union Operators To dict | 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 584 – Add Union Operators To dict | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0584/"> <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 584 – Add Union Operators To dict | peps.python.org'> <meta property="og:description" content="This PEP proposes adding merge (|) and update (|=) operators to the built-in dict class."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0584/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="This PEP proposes adding merge (|) and update (|=) operators to the built-in dict class."> <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 584</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 584 – Add Union Operators To dict</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Steven D’Aprano <steve at pearwood.info>, Brandt Bucher <brandt at python.org></dd> <dt class="field-even">BDFL-Delegate<span class="colon">:</span></dt> <dd class="field-even">Guido van Rossum <guido at python.org></dd> <dt class="field-odd">Status<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd> <dt class="field-even">Type<span class="colon">:</span></dt> <dd class="field-even"><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-odd">Created<span class="colon">:</span></dt> <dd class="field-odd">01-Mar-2019</dd> <dt class="field-even">Python-Version<span class="colon">:</span></dt> <dd class="field-even">3.9</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd">01-Mar-2019, 16-Oct-2019, 02-Dec-2019, 04-Feb-2020, 17-Feb-2020</dd> <dt class="field-even">Resolution<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/python-dev@python.org/thread/6KT2KIOTYXMDCD2CCAOLOI7LUGTN6MBS">Python-Dev thread</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a><ul> <li><a class="reference internal" href="#dict-update"><code class="docutils literal notranslate"><span class="pre">dict.update</span></code></a></li> <li><a class="reference internal" href="#d1-d2"><code class="docutils literal notranslate"><span class="pre">{**d1,</span> <span class="pre">**d2}</span></code></a></li> <li><a class="reference internal" href="#collections-chainmap"><code class="docutils literal notranslate"><span class="pre">collections.ChainMap</span></code></a></li> <li><a class="reference internal" href="#dict-d1-d2"><code class="docutils literal notranslate"><span class="pre">dict(d1,</span> <span class="pre">**d2)</span></code></a></li> </ul> </li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#major-objections">Major Objections</a><ul> <li><a class="reference internal" href="#dict-union-is-not-commutative">Dict Union Is Not Commutative</a><ul> <li><a class="reference internal" href="#response">Response</a></li> </ul> </li> <li><a class="reference internal" href="#dict-union-will-be-inefficient">Dict Union Will Be Inefficient</a><ul> <li><a class="reference internal" href="#id1">Response</a></li> </ul> </li> <li><a class="reference internal" href="#dict-union-is-lossy">Dict Union Is Lossy</a><ul> <li><a class="reference internal" href="#id2">Response</a></li> </ul> </li> <li><a class="reference internal" href="#only-one-way-to-do-it">Only One Way To Do It</a><ul> <li><a class="reference internal" href="#id3">Response</a></li> </ul> </li> <li><a class="reference internal" href="#more-than-one-way-to-do-it">More Than One Way To Do It</a><ul> <li><a class="reference internal" href="#id4">Response</a></li> </ul> </li> <li><a class="reference internal" href="#dict-union-makes-code-harder-to-understand">Dict Union Makes Code Harder To Understand</a><ul> <li><a class="reference internal" href="#id5">Response</a></li> </ul> </li> <li><a class="reference internal" href="#what-about-the-full-set-api">What About The Full <code class="docutils literal notranslate"><span class="pre">set</span></code> API?</a><ul> <li><a class="reference internal" href="#id6">Response</a></li> </ul> </li> <li><a class="reference internal" href="#what-about-mapping-and-mutablemapping">What About <code class="docutils literal notranslate"><span class="pre">Mapping</span></code> And <code class="docutils literal notranslate"><span class="pre">MutableMapping</span></code>?</a><ul> <li><a class="reference internal" href="#id7">Response</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#rejected-semantics">Rejected Semantics</a><ul> <li><a class="reference internal" href="#raise">Raise</a></li> <li><a class="reference internal" href="#add-the-values-as-counter-does-with">Add The Values (As Counter Does, with <code class="docutils literal notranslate"><span class="pre">+</span></code>)</a></li> <li><a class="reference internal" href="#leftmost-value-first-seen-wins">Leftmost Value (First-Seen) Wins</a></li> <li><a class="reference internal" href="#concatenate-values-in-a-list">Concatenate Values In A List</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a><ul> <li><a class="reference internal" href="#use-the-addition-operator">Use The Addition Operator</a></li> <li><a class="reference internal" href="#use-the-left-shift-operator">Use The Left Shift Operator</a></li> <li><a class="reference internal" href="#use-a-new-left-arrow-operator">Use A New Left Arrow Operator</a></li> <li><a class="reference internal" href="#use-a-method">Use A Method</a><ul> <li><a class="reference internal" href="#advantages">Advantages</a></li> <li><a class="reference internal" href="#disadvantages">Disadvantages</a></li> </ul> </li> <li><a class="reference internal" href="#use-a-function">Use a Function</a><ul> <li><a class="reference internal" href="#id8">Advantages</a></li> <li><a class="reference internal" href="#id9">Disadvantages</a></li> </ul> </li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#examples">Examples</a><ul> <li><a class="reference internal" href="#ipython-zmq-ipkernel-py">IPython/zmq/ipkernel.py</a></li> <li><a class="reference internal" href="#ipython-zmq-kernelapp-py">IPython/zmq/kernelapp.py</a></li> <li><a class="reference internal" href="#matplotlib-backends-backend-svg-py">matplotlib/backends/backend_svg.py</a></li> <li><a class="reference internal" href="#matplotlib-delaunay-triangulate-py">matplotlib/delaunay/triangulate.py</a></li> <li><a class="reference internal" href="#matplotlib-legend-py">matplotlib/legend.py</a></li> <li><a class="reference internal" href="#numpy-ma-core-py">numpy/ma/core.py</a></li> <li><a class="reference internal" href="#praw-internal-py">praw/internal.py</a></li> <li><a class="reference internal" href="#pygments-lexer-py">pygments/lexer.py</a></li> <li><a class="reference internal" href="#requests-sessions-py">requests/sessions.py</a></li> <li><a class="reference internal" href="#sphinx-domains-init-py">sphinx/domains/__init__.py</a></li> <li><a class="reference internal" href="#sphinx-ext-doctest-py">sphinx/ext/doctest.py</a></li> <li><a class="reference internal" href="#sphinx-ext-inheritance-diagram-py">sphinx/ext/inheritance_diagram.py</a></li> <li><a class="reference internal" href="#sphinx-highlighting-py">sphinx/highlighting.py</a></li> <li><a class="reference internal" href="#sphinx-quickstart-py">sphinx/quickstart.py</a></li> <li><a class="reference internal" href="#sympy-abc-py">sympy/abc.py</a></li> <li><a class="reference internal" href="#sympy-parsing-maxima-py">sympy/parsing/maxima.py</a></li> <li><a class="reference internal" href="#sympy-printing-ccode-py-and-sympy-printing-fcode-py">sympy/printing/ccode.py and sympy/printing/fcode.py</a></li> <li><a class="reference internal" href="#sympy-utilities-runtests-py">sympy/utilities/runtests.py</a></li> </ul> </li> <li><a class="reference internal" href="#related-discussions">Related Discussions</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP proposes adding merge (<code class="docutils literal notranslate"><span class="pre">|</span></code>) and update (<code class="docutils literal notranslate"><span class="pre">|=</span></code>) operators to the built-in <code class="docutils literal notranslate"><span class="pre">dict</span></code> class.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>After this PEP was accepted, the decision was made to also implement the new operators for <a class="reference external" href="https://bugs.python.org/issue36144">several other standard library mappings</a>.</p> </div> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p>The current ways to merge two dicts have several disadvantages:</p> <section id="dict-update"> <h3><a class="toc-backref" href="#dict-update" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">dict.update</span></code></a></h3> <p><code class="docutils literal notranslate"><span class="pre">d1.update(d2)</span></code> modifies <code class="docutils literal notranslate"><span class="pre">d1</span></code> in-place. <code class="docutils literal notranslate"><span class="pre">e</span> <span class="pre">=</span> <span class="pre">d1.copy();</span> <span class="pre">e.update(d2)</span></code> is not an expression and needs a temporary variable.</p> </section> <section id="d1-d2"> <h3><a class="toc-backref" href="#d1-d2" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">{**d1,</span> <span class="pre">**d2}</span></code></a></h3> <p>Dict unpacking looks ugly and is not easily discoverable. Few people would be able to guess what it means the first time they see it, or think of it as the “obvious way” to merge two dicts.</p> <p><a class="reference external" href="https://mail.python.org/archives/list/python-ideas@python.org/message/K4IC74IXE23K4KEL7OUFK3VBC62HGGVF/">As Guido said</a>:</p> <blockquote> <div>I’m sorry for PEP 448, but even if you know about <code class="docutils literal notranslate"><span class="pre">**d</span></code> in simpler contexts, if you were to ask a typical Python user how to combine two dicts into a new one, I doubt many people would think of <code class="docutils literal notranslate"><span class="pre">{**d1,</span> <span class="pre">**d2}</span></code>. I know I myself had forgotten about it when this thread started!</div></blockquote> <p><code class="docutils literal notranslate"><span class="pre">{**d1,</span> <span class="pre">**d2}</span></code> ignores the types of the mappings and always returns a <code class="docutils literal notranslate"><span class="pre">dict</span></code>. <code class="docutils literal notranslate"><span class="pre">type(d1)({**d1,</span> <span class="pre">**d2})</span></code> fails for dict subclasses such as <code class="docutils literal notranslate"><span class="pre">defaultdict</span></code> that have an incompatible <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method.</p> </section> <section id="collections-chainmap"> <h3><a class="toc-backref" href="#collections-chainmap" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">collections.ChainMap</span></code></a></h3> <p><code class="docutils literal notranslate"><span class="pre">ChainMap</span></code> is unfortunately poorly-known and doesn’t qualify as “obvious”. It also resolves duplicate keys in the opposite order to that expected (“first seen wins” instead of “last seen wins”). Like dict unpacking, it is tricky to get it to honor the desired subclass. For the same reason, <code class="docutils literal notranslate"><span class="pre">type(d1)(ChainMap(d2,</span> <span class="pre">d1))</span></code> fails for some subclasses of dict.</p> <p>Further, ChainMaps wrap their underlying dicts, so writes to the ChainMap will modify the original dict:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">d1</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'spam'</span><span class="p">:</span> <span class="mi">1</span><span class="p">}</span> <span class="gp">>>> </span><span class="n">d2</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'eggs'</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span> <span class="gp">>>> </span><span class="n">merged</span> <span class="o">=</span> <span class="n">ChainMap</span><span class="p">(</span><span class="n">d2</span><span class="p">,</span> <span class="n">d1</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">merged</span><span class="p">[</span><span class="s1">'eggs'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">999</span> <span class="gp">>>> </span><span class="n">d2</span> <span class="go">{'eggs': 999}</span> </pre></div> </div> </section> <section id="dict-d1-d2"> <h3><a class="toc-backref" href="#dict-d1-d2" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">dict(d1,</span> <span class="pre">**d2)</span></code></a></h3> <p>This “neat trick” is not well-known, and only works when <code class="docutils literal notranslate"><span class="pre">d2</span></code> is entirely string-keyed:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">d1</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"spam"</span><span class="p">:</span> <span class="mi">1</span><span class="p">}</span> <span class="gp">>>> </span><span class="n">d2</span> <span class="o">=</span> <span class="p">{</span><span class="mi">3665</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span> <span class="gp">>>> </span><span class="nb">dict</span><span class="p">(</span><span class="n">d1</span><span class="p">,</span> <span class="o">**</span><span class="n">d2</span><span class="p">)</span> <span class="gt">Traceback (most recent call last):</span> <span class="w"> </span><span class="c">...</span> <span class="gr">TypeError</span>: <span class="n">keywords must be strings</span> </pre></div> </div> </section> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>The new operators will have the same relationship to the <code class="docutils literal notranslate"><span class="pre">dict.update</span></code> method as the list concatenate (<code class="docutils literal notranslate"><span class="pre">+</span></code>) and extend (<code class="docutils literal notranslate"><span class="pre">+=</span></code>) operators have to <code class="docutils literal notranslate"><span class="pre">list.extend</span></code>. Note that this is somewhat different from the relationship that <code class="docutils literal notranslate"><span class="pre">|</span></code>/<code class="docutils literal notranslate"><span class="pre">|=</span></code> have with <code class="docutils literal notranslate"><span class="pre">set.update</span></code>; the authors have determined that allowing the in-place operator to accept a wider range of types (as <code class="docutils literal notranslate"><span class="pre">list</span></code> does) is a more useful design, and that restricting the types of the binary operator’s operands (again, as <code class="docutils literal notranslate"><span class="pre">list</span></code> does) will help avoid silent errors caused by complicated implicit type casting on both sides.</p> <p>Key conflicts will be resolved by keeping the rightmost value. This matches the existing behavior of similar <code class="docutils literal notranslate"><span class="pre">dict</span></code> operations, where the last seen value always wins:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="s1">'a'</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'a'</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span> <span class="p">{</span><span class="o">**</span><span class="n">d</span><span class="p">,</span> <span class="o">**</span><span class="n">e</span><span class="p">}</span> <span class="n">d</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="n">d</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="ow">in</span> <span class="n">x</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span> </pre></div> </div> <p>All of the above follow the same rule. This PEP takes the position that this behavior is simple, obvious, usually the behavior we want, and should be the default behavior for dicts. This means that dict union is not commutative; in general <code class="docutils literal notranslate"><span class="pre">d</span> <span class="pre">|</span> <span class="pre">e</span> <span class="pre">!=</span> <span class="pre">e</span> <span class="pre">|</span> <span class="pre">d</span></code>.</p> <p>Similarly, the <em>iteration order</em> of the key-value pairs in the dictionary will follow the same semantics as the examples above, with each newly added key (and its value) being appended to the current sequence.</p> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <p>Dict union will return a new <code class="docutils literal notranslate"><span class="pre">dict</span></code> consisting of the left operand merged with the right operand, each of which must be a <code class="docutils literal notranslate"><span class="pre">dict</span></code> (or an instance of a <code class="docutils literal notranslate"><span class="pre">dict</span></code> subclass). If a key appears in both operands, the last-seen value (i.e. that from the right-hand operand) wins:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">d</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'spam'</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'eggs'</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">'cheese'</span><span class="p">:</span> <span class="mi">3</span><span class="p">}</span> <span class="gp">>>> </span><span class="n">e</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'cheese'</span><span class="p">:</span> <span class="s1">'cheddar'</span><span class="p">,</span> <span class="s1">'aardvark'</span><span class="p">:</span> <span class="s1">'Ethel'</span><span class="p">}</span> <span class="gp">>>> </span><span class="n">d</span> <span class="o">|</span> <span class="n">e</span> <span class="go">{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}</span> <span class="gp">>>> </span><span class="n">e</span> <span class="o">|</span> <span class="n">d</span> <span class="go">{'cheese': 3, 'aardvark': 'Ethel', 'spam': 1, 'eggs': 2}</span> </pre></div> </div> <p>The augmented assignment version operates in-place:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">d</span> <span class="o">|=</span> <span class="n">e</span> <span class="gp">>>> </span><span class="n">d</span> <span class="go">{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}</span> </pre></div> </div> <p>Augmented assignment behaves identically to the <code class="docutils literal notranslate"><span class="pre">update</span></code> method called with a single positional argument, so it also accepts anything implementing the Mapping protocol (more specifically, anything with the <code class="docutils literal notranslate"><span class="pre">keys</span></code> and <code class="docutils literal notranslate"><span class="pre">__getitem__</span></code> methods) or iterables of key-value pairs. This is analogous to <code class="docutils literal notranslate"><span class="pre">list</span> <span class="pre">+=</span></code> and <code class="docutils literal notranslate"><span class="pre">list.extend</span></code>, which accept any iterable, not just lists. Continued from above:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">d</span> <span class="o">|</span> <span class="p">[(</span><span class="s1">'spam'</span><span class="p">,</span> <span class="mi">999</span><span class="p">)]</span> <span class="gt">Traceback (most recent call last):</span> <span class="w"> </span><span class="c">...</span> <span class="gr">TypeError</span>: <span class="n">can only merge dict (not "list") to dict</span> <span class="gp">>>> </span><span class="n">d</span> <span class="o">|=</span> <span class="p">[(</span><span class="s1">'spam'</span><span class="p">,</span> <span class="mi">999</span><span class="p">)]</span> <span class="gp">>>> </span><span class="n">d</span> <span class="go">{'spam': 999, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}</span> </pre></div> </div> <p>When new keys are added, their order matches their order within the right-hand mapping, if any exists for its type.</p> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2> <p>One of the authors has <a class="reference external" href="https://github.com/python/cpython/pull/12088">written a C implementation</a>.</p> <p>An <em>approximate</em> pure-Python implementation is:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="fm">__or__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span> <span class="k">return</span> <span class="bp">NotImplemented</span> <span class="n">new</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="n">new</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="k">return</span> <span class="n">new</span> <span class="k">def</span> <span class="fm">__ror__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span> <span class="k">return</span> <span class="bp">NotImplemented</span> <span class="n">new</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="n">new</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="k">return</span> <span class="n">new</span> <span class="k">def</span> <span class="fm">__ior__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span> <span class="nb">dict</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">)</span> <span class="k">return</span> <span class="bp">self</span> </pre></div> </div> </section> <section id="major-objections"> <h2><a class="toc-backref" href="#major-objections" role="doc-backlink">Major Objections</a></h2> <section id="dict-union-is-not-commutative"> <h3><a class="toc-backref" href="#dict-union-is-not-commutative" role="doc-backlink">Dict Union Is Not Commutative</a></h3> <p>Union is commutative, but dict union will not be (<code class="docutils literal notranslate"><span class="pre">d</span> <span class="pre">|</span> <span class="pre">e</span> <span class="pre">!=</span> <span class="pre">e</span> <span class="pre">|</span> <span class="pre">d</span></code>).</p> <section id="response"> <h4><a class="toc-backref" href="#response" role="doc-backlink">Response</a></h4> <p>There is precedent for non-commutative unions in Python:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="p">{</span><span class="mi">0</span><span class="p">}</span> <span class="o">|</span> <span class="p">{</span><span class="kc">False</span><span class="p">}</span> <span class="go">{0}</span> <span class="gp">>>> </span><span class="p">{</span><span class="kc">False</span><span class="p">}</span> <span class="o">|</span> <span class="p">{</span><span class="mi">0</span><span class="p">}</span> <span class="go">{False}</span> </pre></div> </div> <p>While the results may be equal, they are distinctly different. In general, <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">|</span> <span class="pre">b</span></code> is not the same operation as <code class="docutils literal notranslate"><span class="pre">b</span> <span class="pre">|</span> <span class="pre">a</span></code>.</p> </section> </section> <section id="dict-union-will-be-inefficient"> <h3><a class="toc-backref" href="#dict-union-will-be-inefficient" role="doc-backlink">Dict Union Will Be Inefficient</a></h3> <p>Giving a pipe operator to mappings is an invitation to writing code that doesn’t scale well. Repeated dict union is inefficient: <code class="docutils literal notranslate"><span class="pre">d</span> <span class="pre">|</span> <span class="pre">e</span> <span class="pre">|</span> <span class="pre">f</span> <span class="pre">|</span> <span class="pre">g</span> <span class="pre">|</span> <span class="pre">h</span></code> creates and destroys three temporary mappings.</p> <section id="id1"> <h4><a class="toc-backref" href="#id1" role="doc-backlink">Response</a></h4> <p>The same argument applies to sequence concatenation.</p> <p>Sequence concatenation grows with the total number of items in the sequences, leading to O(N**2) (quadratic) performance. Dict union is likely to involve duplicate keys, so the temporary mappings will not grow as fast.</p> <p>Just as it is rare for people to concatenate large numbers of lists or tuples, the authors of this PEP believe that it will be rare for people to merge large numbers of dicts. <code class="docutils literal notranslate"><span class="pre">collections.Counter</span></code> is a dict subclass that supports many operators, and there are no known examples of people having performance issues due to combining large numbers of Counters. Further, a survey of the standard library by the authors found no examples of merging more than two dicts, so this is unlikely to be a performance problem in practice… “Everything is fast for small enough N”.</p> <p>If one expects to be merging a large number of dicts where performance is an issue, it may be better to use an explicit loop and in-place merging:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">new</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">many_dicts</span><span class="p">:</span> <span class="n">new</span> <span class="o">|=</span> <span class="n">d</span> </pre></div> </div> </section> </section> <section id="dict-union-is-lossy"> <h3><a class="toc-backref" href="#dict-union-is-lossy" role="doc-backlink">Dict Union Is Lossy</a></h3> <p>Dict union can lose data (values may disappear); no other form of union is lossy.</p> <section id="id2"> <h4><a class="toc-backref" href="#id2" role="doc-backlink">Response</a></h4> <p>It isn’t clear why the first part of this argument is a problem. <code class="docutils literal notranslate"><span class="pre">dict.update()</span></code> may throw away values, but not keys; that is expected behavior, and will remain expected behavior regardless of whether it is spelled as <code class="docutils literal notranslate"><span class="pre">update()</span></code> or <code class="docutils literal notranslate"><span class="pre">|</span></code>.</p> <p>Other types of union are also lossy, in the sense of not being reversible; you cannot get back the two operands given only the union. <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">|</span> <span class="pre">b</span> <span class="pre">==</span> <span class="pre">365</span></code>… what are <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">b</span></code>?</p> </section> </section> <section id="only-one-way-to-do-it"> <h3><a class="toc-backref" href="#only-one-way-to-do-it" role="doc-backlink">Only One Way To Do It</a></h3> <p>Dict union will violate the Only One Way koan from the Zen.</p> <section id="id3"> <h4><a class="toc-backref" href="#id3" role="doc-backlink">Response</a></h4> <p>There is no such koan. “Only One Way” is a calumny about Python originating long ago from the Perl community.</p> </section> </section> <section id="more-than-one-way-to-do-it"> <h3><a class="toc-backref" href="#more-than-one-way-to-do-it" role="doc-backlink">More Than One Way To Do It</a></h3> <p>Okay, the Zen doesn’t say that there should be Only One Way To Do It. But it does have a prohibition against allowing “more than one way to do it”.</p> <section id="id4"> <h4><a class="toc-backref" href="#id4" role="doc-backlink">Response</a></h4> <p>There is no such prohibition. The “Zen of Python” merely expresses a <em>preference</em> for “only one <em>obvious</em> way”:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">There</span> <span class="n">should</span> <span class="n">be</span> <span class="n">one</span><span class="o">--</span> <span class="ow">and</span> <span class="n">preferably</span> <span class="n">only</span> <span class="n">one</span> <span class="o">--</span><span class="n">obvious</span> <span class="n">way</span> <span class="n">to</span> <span class="n">do</span> <span class="n">it</span><span class="o">.</span> </pre></div> </div> <p>The emphasis here is that there should be an obvious way to do “it”. In the case of dict update operations, there are at least two different operations that we might wish to do:</p> <ul class="simple"> <li><em>Update a dict in place</em>: The Obvious Way is to use the <code class="docutils literal notranslate"><span class="pre">update()</span></code> method. If this proposal is accepted, the <code class="docutils literal notranslate"><span class="pre">|=</span></code> augmented assignment operator will also work, but that is a side-effect of how augmented assignments are defined. Which you choose is a matter of taste.</li> <li><em>Merge two existing dicts into a third, new dict</em>: This PEP proposes that the Obvious Way is to use the <code class="docutils literal notranslate"><span class="pre">|</span></code> merge operator.</li> </ul> <p>In practice, this preference for “only one way” is frequently violated in Python. For example, every <code class="docutils literal notranslate"><span class="pre">for</span></code> loop could be re-written as a <code class="docutils literal notranslate"><span class="pre">while</span></code> loop; every <code class="docutils literal notranslate"><span class="pre">if</span></code> block could be written as an <code class="docutils literal notranslate"><span class="pre">if</span></code>/ <code class="docutils literal notranslate"><span class="pre">else</span></code> block. List, set and dict comprehensions could all be replaced by generator expressions. Lists offer no fewer than five ways to implement concatenation:</p> <ul class="simple"> <li>Concatenation operator: <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">+</span> <span class="pre">b</span></code></li> <li>In-place concatenation operator: <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">+=</span> <span class="pre">b</span></code></li> <li>Slice assignment: <code class="docutils literal notranslate"><span class="pre">a[len(a):]</span> <span class="pre">=</span> <span class="pre">b</span></code></li> <li>Sequence unpacking: <code class="docutils literal notranslate"><span class="pre">[*a,</span> <span class="pre">*b]</span></code></li> <li>Extend method: <code class="docutils literal notranslate"><span class="pre">a.extend(b)</span></code></li> </ul> <p>We should not be too strict about rejecting useful functionality because it violates “only one way”.</p> </section> </section> <section id="dict-union-makes-code-harder-to-understand"> <h3><a class="toc-backref" href="#dict-union-makes-code-harder-to-understand" role="doc-backlink">Dict Union Makes Code Harder To Understand</a></h3> <p>Dict union makes it harder to tell what code means. To paraphrase the objection rather than quote anyone in specific: “If I see <code class="docutils literal notranslate"><span class="pre">spam</span> <span class="pre">|</span> <span class="pre">eggs</span></code>, I can’t tell what it does unless I know what <code class="docutils literal notranslate"><span class="pre">spam</span></code> and <code class="docutils literal notranslate"><span class="pre">eggs</span></code> are”.</p> <section id="id5"> <h4><a class="toc-backref" href="#id5" role="doc-backlink">Response</a></h4> <p>This is very true. But it is equally true today, where the use of the <code class="docutils literal notranslate"><span class="pre">|</span></code> operator could mean any of:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">int</span></code>/<code class="docutils literal notranslate"><span class="pre">bool</span></code> bitwise-or</li> <li><code class="docutils literal notranslate"><span class="pre">set</span></code>/<code class="docutils literal notranslate"><span class="pre">frozenset</span></code> union</li> <li>any other overloaded operation</li> </ul> <p>Adding dict union to the set of possibilities doesn’t seem to make it <em>harder</em> to understand the code. No more work is required to determine that <code class="docutils literal notranslate"><span class="pre">spam</span></code> and <code class="docutils literal notranslate"><span class="pre">eggs</span></code> are mappings than it would take to determine that they are sets, or integers. And good naming conventions will help:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">flags</span> <span class="o">|=</span> <span class="n">WRITEABLE</span> <span class="c1"># Probably numeric bitwise-or.</span> <span class="n">DO_NOT_RUN</span> <span class="o">=</span> <span class="n">WEEKENDS</span> <span class="o">|</span> <span class="n">HOLIDAYS</span> <span class="c1"># Probably set union.</span> <span class="n">settings</span> <span class="o">=</span> <span class="n">DEFAULT_SETTINGS</span> <span class="o">|</span> <span class="n">user_settings</span> <span class="o">|</span> <span class="n">workspace_settings</span> <span class="c1"># Probably dict union.</span> </pre></div> </div> </section> </section> <section id="what-about-the-full-set-api"> <h3><a class="toc-backref" href="#what-about-the-full-set-api" role="doc-backlink">What About The Full <code class="docutils literal notranslate"><span class="pre">set</span></code> API?</a></h3> <p>dicts are “set like”, and should support the full collection of set operators: <code class="docutils literal notranslate"><span class="pre">|</span></code>, <code class="docutils literal notranslate"><span class="pre">&</span></code>, <code class="docutils literal notranslate"><span class="pre">^</span></code>, and <code class="docutils literal notranslate"><span class="pre">-</span></code>.</p> <section id="id6"> <h4><a class="toc-backref" href="#id6" role="doc-backlink">Response</a></h4> <p>This PEP does not take a position on whether dicts should support the full collection of set operators, and would prefer to leave that for a later PEP (one of the authors is interested in drafting such a PEP). For the benefit of any later PEP, a brief summary follows.</p> <p>Set symmetric difference (<code class="docutils literal notranslate"><span class="pre">^</span></code>) is obvious and natural. For example, given two dicts:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">d1</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"spam"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">"eggs"</span><span class="p">:</span> <span class="mi">2</span><span class="p">}</span> <span class="n">d2</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"ham"</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">"eggs"</span><span class="p">:</span> <span class="mi">4</span><span class="p">}</span> </pre></div> </div> <p>the symmetric difference <code class="docutils literal notranslate"><span class="pre">d1</span> <span class="pre">^</span> <span class="pre">d2</span></code> would be <code class="docutils literal notranslate"><span class="pre">{"spam":</span> <span class="pre">1,</span> <span class="pre">"ham":</span> <span class="pre">3}</span></code>.</p> <p>Set difference (<code class="docutils literal notranslate"><span class="pre">-</span></code>) is also obvious and natural, and an earlier version of this PEP included it in the proposal. Given the dicts above, we would have <code class="docutils literal notranslate"><span class="pre">d1</span> <span class="pre">-</span> <span class="pre">d2</span></code> be <code class="docutils literal notranslate"><span class="pre">{"spam":</span> <span class="pre">1}</span></code> and <code class="docutils literal notranslate"><span class="pre">d2</span> <span class="pre">-</span> <span class="pre">d1</span></code> be <code class="docutils literal notranslate"><span class="pre">{"ham":</span> <span class="pre">3}</span></code>.</p> <p>Set intersection (<code class="docutils literal notranslate"><span class="pre">&</span></code>) is a bit more problematic. While it is easy to determine the intersection of <em>keys</em> in two dicts, it is not clear what to do with the <em>values</em>. Given the two dicts above, it is obvious that the only key of <code class="docutils literal notranslate"><span class="pre">d1</span> <span class="pre">&</span> <span class="pre">d2</span></code> must be <code class="docutils literal notranslate"><span class="pre">"eggs"</span></code>. “Last seen wins”, however, has the advantage of consistency with other dict operations (and the proposed union operators).</p> </section> </section> <section id="what-about-mapping-and-mutablemapping"> <h3><a class="toc-backref" href="#what-about-mapping-and-mutablemapping" role="doc-backlink">What About <code class="docutils literal notranslate"><span class="pre">Mapping</span></code> And <code class="docutils literal notranslate"><span class="pre">MutableMapping</span></code>?</a></h3> <p><code class="docutils literal notranslate"><span class="pre">collections.abc.Mapping</span></code> and <code class="docutils literal notranslate"><span class="pre">collections.abc.MutableMapping</span></code> should define <code class="docutils literal notranslate"><span class="pre">|</span></code> and <code class="docutils literal notranslate"><span class="pre">|=</span></code>, so subclasses could just inherit the new operators instead of having to define them.</p> <section id="id7"> <h4><a class="toc-backref" href="#id7" role="doc-backlink">Response</a></h4> <p>There are two primary reasons why adding the new operators to these classes would be problematic:</p> <ul class="simple"> <li>Currently, neither defines a <code class="docutils literal notranslate"><span class="pre">copy</span></code> method, which would be necessary for <code class="docutils literal notranslate"><span class="pre">|</span></code> to create a new instance.</li> <li>Adding <code class="docutils literal notranslate"><span class="pre">|=</span></code> to <code class="docutils literal notranslate"><span class="pre">MutableMapping</span></code> (or a <code class="docutils literal notranslate"><span class="pre">copy</span></code> method to <code class="docutils literal notranslate"><span class="pre">Mapping</span></code>) would create compatibility issues for virtual subclasses.</li> </ul> </section> </section> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> <section id="rejected-semantics"> <h3><a class="toc-backref" href="#rejected-semantics" role="doc-backlink">Rejected Semantics</a></h3> <p>There were at least four other proposed solutions for handling conflicting keys. These alternatives are left to subclasses of dict.</p> <section id="raise"> <h4><a class="toc-backref" href="#raise" role="doc-backlink">Raise</a></h4> <p>It isn’t clear that this behavior has many use-cases or will be often useful, but it will likely be annoying as any use of the dict union operator would have to be guarded with a <code class="docutils literal notranslate"><span class="pre">try</span></code>/<code class="docutils literal notranslate"><span class="pre">except</span></code> clause.</p> </section> <section id="add-the-values-as-counter-does-with"> <h4><a class="toc-backref" href="#add-the-values-as-counter-does-with" role="doc-backlink">Add The Values (As Counter Does, with <code class="docutils literal notranslate"><span class="pre">+</span></code>)</a></h4> <p>Too specialised to be used as the default behavior.</p> </section> <section id="leftmost-value-first-seen-wins"> <h4><a class="toc-backref" href="#leftmost-value-first-seen-wins" role="doc-backlink">Leftmost Value (First-Seen) Wins</a></h4> <p>It isn’t clear that this behavior has many use-cases. In fact, one can simply reverse the order of the arguments:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">d2</span> <span class="o">|</span> <span class="n">d1</span> <span class="c1"># d1 merged with d2, keeping existing values in d1</span> </pre></div> </div> </section> <section id="concatenate-values-in-a-list"> <h4><a class="toc-backref" href="#concatenate-values-in-a-list" role="doc-backlink">Concatenate Values In A List</a></h4> <p>This is likely to be too specialised to be the default. It is not clear what to do if the values are already lists:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="s1">'a'</span><span class="p">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]}</span> <span class="o">|</span> <span class="p">{</span><span class="s1">'a'</span><span class="p">:</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]}</span> </pre></div> </div> <p>Should this give <code class="docutils literal notranslate"><span class="pre">{'a':</span> <span class="pre">[1,</span> <span class="pre">2,</span> <span class="pre">3,</span> <span class="pre">4]}</span></code> or <code class="docutils literal notranslate"><span class="pre">{'a':</span> <span class="pre">[[1,</span> <span class="pre">2],</span> <span class="pre">[3,</span> <span class="pre">4]]}</span></code>?</p> </section> </section> <section id="rejected-alternatives"> <h3><a class="toc-backref" href="#rejected-alternatives" role="doc-backlink">Rejected Alternatives</a></h3> <section id="use-the-addition-operator"> <h4><a class="toc-backref" href="#use-the-addition-operator" role="doc-backlink">Use The Addition Operator</a></h4> <p>This PEP originally started life as a proposal for dict addition, using the <code class="docutils literal notranslate"><span class="pre">+</span></code> and <code class="docutils literal notranslate"><span class="pre">+=</span></code> operator. That choice proved to be exceedingly controversial, with many people having serious objections to the choice of operator. For details, see <a class="reference external" href="https://github.com/python/peps/commits/master/pep-0584.rst">previous versions</a> of the PEP and the mailing list <a class="reference internal" href="#discussions">discussions</a>.</p> </section> <section id="use-the-left-shift-operator"> <h4><a class="toc-backref" href="#use-the-left-shift-operator" role="doc-backlink">Use The Left Shift Operator</a></h4> <p>The <code class="docutils literal notranslate"><span class="pre"><<</span></code> operator didn’t seem to get much support on Python-Ideas, but no major objections either. Perhaps the strongest objection was Chris Angelico’s comment</p> <blockquote> <div>The “cuteness” value of abusing the operator to indicate information flow got old shortly after C++ did it.</div></blockquote> </section> <section id="use-a-new-left-arrow-operator"> <h4><a class="toc-backref" href="#use-a-new-left-arrow-operator" role="doc-backlink">Use A New Left Arrow Operator</a></h4> <p>Another suggestion was to create a new operator <code class="docutils literal notranslate"><span class="pre"><-</span></code>. Unfortunately this would be ambiguous, <code class="docutils literal notranslate"><span class="pre">d</span> <span class="pre"><-</span> <span class="pre">e</span></code> could mean <code class="docutils literal notranslate"><span class="pre">d</span> <span class="pre">merge</span> <span class="pre">e</span></code> or <code class="docutils literal notranslate"><span class="pre">d</span> <span class="pre">less-than</span> <span class="pre">minus</span> <span class="pre">e</span></code>.</p> </section> <section id="use-a-method"> <h4><a class="toc-backref" href="#use-a-method" role="doc-backlink">Use A Method</a></h4> <p>A <code class="docutils literal notranslate"><span class="pre">dict.merged()</span></code> method would avoid the need for an operator at all. One subtlety is that it would likely need slightly different implementations when called as an unbound method versus as a bound method.</p> <p>As an unbound method, the behavior could be similar to:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">merged</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">mappings</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span> <span class="n">new</span> <span class="o">=</span> <span class="bp">cls</span><span class="p">()</span> <span class="c1"># Will this work for defaultdict?</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">mappings</span><span class="p">:</span> <span class="n">new</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">m</span><span class="p">)</span> <span class="n">new</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">kw</span><span class="p">)</span> <span class="k">return</span> <span class="n">new</span> </pre></div> </div> <p>As a bound method, the behavior could be similar to:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">merged</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">mappings</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span> <span class="n">new</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">mappings</span><span class="p">:</span> <span class="n">new</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">m</span><span class="p">)</span> <span class="n">new</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">kw</span><span class="p">)</span> <span class="k">return</span> <span class="n">new</span> </pre></div> </div> <section id="advantages"> <h5><a class="toc-backref" href="#advantages" role="doc-backlink">Advantages</a></h5> <ul class="simple"> <li>Arguably, methods are more discoverable than operators.</li> <li>The method could accept any number of positional and keyword arguments, avoiding the inefficiency of creating temporary dicts.</li> <li>Accepts sequences of <code class="docutils literal notranslate"><span class="pre">(key,</span> <span class="pre">value)</span></code> pairs like the <code class="docutils literal notranslate"><span class="pre">update</span></code> method.</li> <li>Being a method, it is easy to override in a subclass if you need alternative behaviors such as “first wins”, “unique keys”, etc.</li> </ul> </section> <section id="disadvantages"> <h5><a class="toc-backref" href="#disadvantages" role="doc-backlink">Disadvantages</a></h5> <ul class="simple"> <li>Would likely require a new kind of method decorator which combined the behavior of regular instance methods and <code class="docutils literal notranslate"><span class="pre">classmethod</span></code>. It would need to be public (but not necessarily a builtin) for those needing to override the method. There is a <a class="reference external" href="http://code.activestate.com/recipes/577030">proof of concept</a>.</li> <li>It isn’t an operator. Guido discusses <a class="reference external" href="https://mail.python.org/archives/list/python-ideas@python.org/message/52DLME5DKNZYFEETCTRENRNKWJ2B4DD5/">why operators are useful</a>. For another viewpoint, see <a class="reference external" href="https://www.curiousefficiency.org/posts/2019/03/what-does-x-equals-a-plus-b-mean.html">Alyssa Coghlan’s blog post</a>.</li> </ul> </section> </section> <section id="use-a-function"> <h4><a class="toc-backref" href="#use-a-function" role="doc-backlink">Use a Function</a></h4> <p>Instead of a method, use a new built-in function <code class="docutils literal notranslate"><span class="pre">merged()</span></code>. One possible implementation could be something like this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">merged</span><span class="p">(</span><span class="o">*</span><span class="n">mappings</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span> <span class="k">if</span> <span class="n">mappings</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">mappings</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nb">dict</span><span class="p">):</span> <span class="c1"># If the first argument is a dict, use its type.</span> <span class="n">new</span> <span class="o">=</span> <span class="n">mappings</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="n">mappings</span> <span class="o">=</span> <span class="n">mappings</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="c1"># No positional arguments, or the first argument is a</span> <span class="c1"># sequence of (key, value) pairs.</span> <span class="n">new</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">mappings</span><span class="p">:</span> <span class="n">new</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">m</span><span class="p">)</span> <span class="n">new</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">kw</span><span class="p">)</span> <span class="k">return</span> <span class="n">new</span> </pre></div> </div> <p>An alternative might be to forgo the arbitrary keywords, and take a single keyword parameter that specifies the behavior on collisions:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">merged</span><span class="p">(</span><span class="o">*</span><span class="n">mappings</span><span class="p">,</span> <span class="n">on_collision</span><span class="o">=</span><span class="k">lambda</span> <span class="n">k</span><span class="p">,</span> <span class="n">v1</span><span class="p">,</span> <span class="n">v2</span><span class="p">:</span> <span class="n">v2</span><span class="p">):</span> <span class="c1"># implementation left as an exercise to the reader</span> </pre></div> </div> <section id="id8"> <h5><a class="toc-backref" href="#id8" role="doc-backlink">Advantages</a></h5> <ul class="simple"> <li>Most of the same advantages of the method solutions above.</li> <li>Doesn’t require a subclass to implement alternative behavior on collisions, just a function.</li> </ul> </section> <section id="id9"> <h5><a class="toc-backref" href="#id9" role="doc-backlink">Disadvantages</a></h5> <ul class="simple"> <li>May not be important enough to be a builtin.</li> <li>Hard to override behavior if you need something like “first wins”, without losing the ability to process arbitrary keyword arguments.</li> </ul> </section> </section> </section> </section> <section id="examples"> <h2><a class="toc-backref" href="#examples" role="doc-backlink">Examples</a></h2> <p>The authors of this PEP did a survey of third party libraries for dictionary merging which might be candidates for dict union.</p> <p>This is a cursory list based on a subset of whatever arbitrary third-party packages happened to be installed on one of the authors’ computers, and may not reflect the current state of any package. Also note that, while further (unrelated) refactoring may be possible, the rewritten version only adds usage of the new operators for an apples-to-apples comparison. It also reduces the result to an expression when it is efficient to do so.</p> <section id="ipython-zmq-ipkernel-py"> <h3><a class="toc-backref" href="#ipython-zmq-ipkernel-py" role="doc-backlink">IPython/zmq/ipkernel.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">aliases</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">kernel_aliases</span><span class="p">)</span> <span class="n">aliases</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">shell_aliases</span><span class="p">)</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">aliases</span> <span class="o">=</span> <span class="n">kernel_aliases</span> <span class="o">|</span> <span class="n">shell_aliases</span> </pre></div> </div> </section> <section id="ipython-zmq-kernelapp-py"> <h3><a class="toc-backref" href="#ipython-zmq-kernelapp-py" role="doc-backlink">IPython/zmq/kernelapp.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">kernel_aliases</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">base_aliases</span><span class="p">)</span> <span class="n">kernel_aliases</span><span class="o">.</span><span class="n">update</span><span class="p">({</span> <span class="s1">'ip'</span> <span class="p">:</span> <span class="s1">'KernelApp.ip'</span><span class="p">,</span> <span class="s1">'hb'</span> <span class="p">:</span> <span class="s1">'KernelApp.hb_port'</span><span class="p">,</span> <span class="s1">'shell'</span> <span class="p">:</span> <span class="s1">'KernelApp.shell_port'</span><span class="p">,</span> <span class="s1">'iopub'</span> <span class="p">:</span> <span class="s1">'KernelApp.iopub_port'</span><span class="p">,</span> <span class="s1">'stdin'</span> <span class="p">:</span> <span class="s1">'KernelApp.stdin_port'</span><span class="p">,</span> <span class="s1">'parent'</span><span class="p">:</span> <span class="s1">'KernelApp.parent'</span><span class="p">,</span> <span class="p">})</span> <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">platform</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">'win'</span><span class="p">):</span> <span class="n">kernel_aliases</span><span class="p">[</span><span class="s1">'interrupt'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'KernelApp.interrupt'</span> <span class="n">kernel_flags</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">base_flags</span><span class="p">)</span> <span class="n">kernel_flags</span><span class="o">.</span><span class="n">update</span><span class="p">({</span> <span class="s1">'no-stdout'</span> <span class="p">:</span> <span class="p">(</span> <span class="p">{</span><span class="s1">'KernelApp'</span> <span class="p">:</span> <span class="p">{</span><span class="s1">'no_stdout'</span> <span class="p">:</span> <span class="kc">True</span><span class="p">}},</span> <span class="s2">"redirect stdout to the null device"</span><span class="p">),</span> <span class="s1">'no-stderr'</span> <span class="p">:</span> <span class="p">(</span> <span class="p">{</span><span class="s1">'KernelApp'</span> <span class="p">:</span> <span class="p">{</span><span class="s1">'no_stderr'</span> <span class="p">:</span> <span class="kc">True</span><span class="p">}},</span> <span class="s2">"redirect stderr to the null device"</span><span class="p">),</span> <span class="p">})</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">kernel_aliases</span> <span class="o">=</span> <span class="n">base_aliases</span> <span class="o">|</span> <span class="p">{</span> <span class="s1">'ip'</span> <span class="p">:</span> <span class="s1">'KernelApp.ip'</span><span class="p">,</span> <span class="s1">'hb'</span> <span class="p">:</span> <span class="s1">'KernelApp.hb_port'</span><span class="p">,</span> <span class="s1">'shell'</span> <span class="p">:</span> <span class="s1">'KernelApp.shell_port'</span><span class="p">,</span> <span class="s1">'iopub'</span> <span class="p">:</span> <span class="s1">'KernelApp.iopub_port'</span><span class="p">,</span> <span class="s1">'stdin'</span> <span class="p">:</span> <span class="s1">'KernelApp.stdin_port'</span><span class="p">,</span> <span class="s1">'parent'</span><span class="p">:</span> <span class="s1">'KernelApp.parent'</span><span class="p">,</span> <span class="p">}</span> <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">platform</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">'win'</span><span class="p">):</span> <span class="n">kernel_aliases</span><span class="p">[</span><span class="s1">'interrupt'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'KernelApp.interrupt'</span> <span class="n">kernel_flags</span> <span class="o">=</span> <span class="n">base_flags</span> <span class="o">|</span> <span class="p">{</span> <span class="s1">'no-stdout'</span> <span class="p">:</span> <span class="p">(</span> <span class="p">{</span><span class="s1">'KernelApp'</span> <span class="p">:</span> <span class="p">{</span><span class="s1">'no_stdout'</span> <span class="p">:</span> <span class="kc">True</span><span class="p">}},</span> <span class="s2">"redirect stdout to the null device"</span><span class="p">),</span> <span class="s1">'no-stderr'</span> <span class="p">:</span> <span class="p">(</span> <span class="p">{</span><span class="s1">'KernelApp'</span> <span class="p">:</span> <span class="p">{</span><span class="s1">'no_stderr'</span> <span class="p">:</span> <span class="kc">True</span><span class="p">}},</span> <span class="s2">"redirect stderr to the null device"</span><span class="p">),</span> <span class="p">}</span> </pre></div> </div> </section> <section id="matplotlib-backends-backend-svg-py"> <h3><a class="toc-backref" href="#matplotlib-backends-backend-svg-py" role="doc-backlink">matplotlib/backends/backend_svg.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">attrib</span> <span class="o">=</span> <span class="n">attrib</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="n">attrib</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">extra</span><span class="p">)</span> <span class="n">attrib</span> <span class="o">=</span> <span class="n">attrib</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">attrib</span> <span class="o">=</span> <span class="p">(</span><span class="n">attrib</span> <span class="o">|</span> <span class="n">extra</span><span class="p">)</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> </pre></div> </div> </section> <section id="matplotlib-delaunay-triangulate-py"> <h3><a class="toc-backref" href="#matplotlib-delaunay-triangulate-py" role="doc-backlink">matplotlib/delaunay/triangulate.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">edges</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">edges</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">0</span><span class="p">]][:,</span><span class="mi">1</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">0</span><span class="p">]][:,</span><span class="mi">2</span><span class="p">])))</span> <span class="n">edges</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">1</span><span class="p">]][:,</span><span class="mi">2</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">1</span><span class="p">]][:,</span><span class="mi">0</span><span class="p">])))</span> <span class="n">edges</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">2</span><span class="p">]][:,</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">2</span><span class="p">]][:,</span><span class="mi">1</span><span class="p">])))</span> </pre></div> </div> <p>Rewrite as:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">edges</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">edges</span> <span class="o">|=</span> <span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">0</span><span class="p">]][:,</span><span class="mi">1</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">0</span><span class="p">]][:,</span><span class="mi">2</span><span class="p">])</span> <span class="n">edges</span> <span class="o">|=</span> <span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">1</span><span class="p">]][:,</span><span class="mi">2</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">1</span><span class="p">]][:,</span><span class="mi">0</span><span class="p">])</span> <span class="n">edges</span> <span class="o">|=</span> <span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">2</span><span class="p">]][:,</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">triangle_nodes</span><span class="p">[</span><span class="n">border</span><span class="p">[:,</span><span class="mi">2</span><span class="p">]][:,</span><span class="mi">1</span><span class="p">])</span> </pre></div> </div> </section> <section id="matplotlib-legend-py"> <h3><a class="toc-backref" href="#matplotlib-legend-py" role="doc-backlink">matplotlib/legend.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">hm</span> <span class="o">=</span> <span class="n">default_handler_map</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="n">hm</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_handler_map</span><span class="p">)</span> <span class="k">return</span> <span class="n">hm</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">return</span> <span class="n">default_handler_map</span> <span class="o">|</span> <span class="bp">self</span><span class="o">.</span><span class="n">_handler_map</span> </pre></div> </div> </section> <section id="numpy-ma-core-py"> <h3><a class="toc-backref" href="#numpy-ma-core-py" role="doc-backlink">numpy/ma/core.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_optinfo</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">_optinfo</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s1">'_optinfo'</span><span class="p">,</span> <span class="p">{}))</span> <span class="n">_optinfo</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s1">'_basedict'</span><span class="p">,</span> <span class="p">{}))</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">MaskedArray</span><span class="p">):</span> <span class="n">_optinfo</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s1">'__dict__'</span><span class="p">,</span> <span class="p">{}))</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_optinfo</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">_optinfo</span> <span class="o">|=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s1">'_optinfo'</span><span class="p">,</span> <span class="p">{})</span> <span class="n">_optinfo</span> <span class="o">|=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s1">'_basedict'</span><span class="p">,</span> <span class="p">{})</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">MaskedArray</span><span class="p">):</span> <span class="n">_optinfo</span> <span class="o">|=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s1">'__dict__'</span><span class="p">,</span> <span class="p">{})</span> </pre></div> </div> </section> <section id="praw-internal-py"> <h3><a class="toc-backref" href="#praw-internal-py" role="doc-backlink">praw/internal.py</a></h3> <p>Before:</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="s1">'name'</span><span class="p">:</span> <span class="n">six</span><span class="o">.</span><span class="n">text_type</span><span class="p">(</span><span class="n">user</span><span class="p">),</span> <span class="s1">'type'</span><span class="p">:</span> <span class="n">relationship</span><span class="p">}</span> <span class="n">data</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">kwargs</span><span class="p">)</span> </pre></div> </div> <p>After:</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="s1">'name'</span><span class="p">:</span> <span class="n">six</span><span class="o">.</span><span class="n">text_type</span><span class="p">(</span><span class="n">user</span><span class="p">),</span> <span class="s1">'type'</span><span class="p">:</span> <span class="n">relationship</span><span class="p">}</span> <span class="o">|</span> <span class="n">kwargs</span> </pre></div> </div> </section> <section id="pygments-lexer-py"> <h3><a class="toc-backref" href="#pygments-lexer-py" role="doc-backlink">pygments/lexer.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">kwargs</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">lexer</span><span class="o">.</span><span class="n">options</span><span class="p">)</span> <span class="n">lx</span> <span class="o">=</span> <span class="n">lexer</span><span class="o">.</span><span class="vm">__class__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">lx</span> <span class="o">=</span> <span class="n">lexer</span><span class="o">.</span><span class="vm">__class__</span><span class="p">(</span><span class="o">**</span><span class="p">(</span><span class="n">kwargs</span> <span class="o">|</span> <span class="n">lexer</span><span class="o">.</span><span class="n">options</span><span class="p">))</span> </pre></div> </div> </section> <section id="requests-sessions-py"> <h3><a class="toc-backref" href="#requests-sessions-py" role="doc-backlink">requests/sessions.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">merged_setting</span> <span class="o">=</span> <span class="n">dict_class</span><span class="p">(</span><span class="n">to_key_val_list</span><span class="p">(</span><span class="n">session_setting</span><span class="p">))</span> <span class="n">merged_setting</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">to_key_val_list</span><span class="p">(</span><span class="n">request_setting</span><span class="p">))</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">merged_setting</span> <span class="o">=</span> <span class="n">dict_class</span><span class="p">(</span><span class="n">to_key_val_list</span><span class="p">(</span><span class="n">session_setting</span><span class="p">))</span> <span class="o">|</span> <span class="n">to_key_val_list</span><span class="p">(</span><span class="n">request_setting</span><span class="p">)</span> </pre></div> </div> </section> <section id="sphinx-domains-init-py"> <h3><a class="toc-backref" href="#sphinx-domains-init-py" role="doc-backlink">sphinx/domains/__init__.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">attrs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">known_attrs</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">attrs</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">attrs</span><span class="p">)</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">attrs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">known_attrs</span> <span class="o">|</span> <span class="n">attrs</span> </pre></div> </div> </section> <section id="sphinx-ext-doctest-py"> <h3><a class="toc-backref" href="#sphinx-ext-doctest-py" role="doc-backlink">sphinx/ext/doctest.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">new_opt</span> <span class="o">=</span> <span class="n">code</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="n">new_opt</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">example</span><span class="o">.</span><span class="n">options</span><span class="p">)</span> <span class="n">example</span><span class="o">.</span><span class="n">options</span> <span class="o">=</span> <span class="n">new_opt</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">example</span><span class="o">.</span><span class="n">options</span> <span class="o">=</span> <span class="n">code</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">options</span> <span class="o">|</span> <span class="n">example</span><span class="o">.</span><span class="n">options</span> </pre></div> </div> </section> <section id="sphinx-ext-inheritance-diagram-py"> <h3><a class="toc-backref" href="#sphinx-ext-inheritance-diagram-py" role="doc-backlink">sphinx/ext/inheritance_diagram.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">n_attrs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">default_node_attrs</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="n">e_attrs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">default_edge_attrs</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="n">g_attrs</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">graph_attrs</span><span class="p">)</span> <span class="n">n_attrs</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">node_attrs</span><span class="p">)</span> <span class="n">e_attrs</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">edge_attrs</span><span class="p">)</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">g_attrs</span> <span class="o">|=</span> <span class="n">graph_attrs</span> <span class="n">n_attrs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">default_node_attrs</span> <span class="o">|</span> <span class="n">node_attrs</span> <span class="n">e_attrs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">default_edge_attrs</span> <span class="o">|</span> <span class="n">edge_attrs</span> </pre></div> </div> </section> <section id="sphinx-highlighting-py"> <h3><a class="toc-backref" href="#sphinx-highlighting-py" role="doc-backlink">sphinx/highlighting.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">kwargs</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">formatter_args</span><span class="p">)</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">formatter</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">formatter</span><span class="p">(</span><span class="o">**</span><span class="p">(</span><span class="n">kwargs</span> <span class="o">|</span> <span class="bp">self</span><span class="o">.</span><span class="n">formatter_args</span><span class="p">))</span> </pre></div> </div> </section> <section id="sphinx-quickstart-py"> <h3><a class="toc-backref" href="#sphinx-quickstart-py" role="doc-backlink">sphinx/quickstart.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">d2</span> <span class="o">=</span> <span class="n">DEFAULT_VALUE</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="n">d2</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">dict</span><span class="p">((</span><span class="s2">"ext_"</span><span class="o">+</span><span class="n">ext</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span> <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="n">EXTENSIONS</span><span class="p">))</span> <span class="n">d2</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="n">d</span> <span class="o">=</span> <span class="n">d2</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">d</span> <span class="o">=</span> <span class="n">DEFAULT_VALUE</span> <span class="o">|</span> <span class="nb">dict</span><span class="p">((</span><span class="s2">"ext_"</span><span class="o">+</span><span class="n">ext</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span> <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="n">EXTENSIONS</span><span class="p">)</span> <span class="o">|</span> <span class="n">d</span> </pre></div> </div> </section> <section id="sympy-abc-py"> <h3><a class="toc-backref" href="#sympy-abc-py" role="doc-backlink">sympy/abc.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">clash</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">clash</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">clash1</span><span class="p">)</span> <span class="n">clash</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">clash2</span><span class="p">)</span> <span class="k">return</span> <span class="n">clash1</span><span class="p">,</span> <span class="n">clash2</span><span class="p">,</span> <span class="n">clash</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">return</span> <span class="n">clash1</span><span class="p">,</span> <span class="n">clash2</span><span class="p">,</span> <span class="n">clash1</span> <span class="o">|</span> <span class="n">clash2</span> </pre></div> </div> </section> <section id="sympy-parsing-maxima-py"> <h3><a class="toc-backref" href="#sympy-parsing-maxima-py" role="doc-backlink">sympy/parsing/maxima.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">dct</span> <span class="o">=</span> <span class="n">MaximaHelpers</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="n">dct</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">name_dict</span><span class="p">)</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">sympify</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="nb">locals</span><span class="o">=</span><span class="n">dct</span><span class="p">)</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">obj</span> <span class="o">=</span> <span class="n">sympify</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="nb">locals</span><span class="o">=</span><span class="n">MaximaHelpers</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">|</span><span class="n">name_dict</span><span class="p">)</span> </pre></div> </div> </section> <section id="sympy-printing-ccode-py-and-sympy-printing-fcode-py"> <h3><a class="toc-backref" href="#sympy-printing-ccode-py-and-sympy-printing-fcode-py" role="doc-backlink">sympy/printing/ccode.py and sympy/printing/fcode.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">known_functions</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">known_functions</span><span class="p">)</span> <span class="n">userfuncs</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'user_functions'</span><span class="p">,</span> <span class="p">{})</span> <span class="bp">self</span><span class="o">.</span><span class="n">known_functions</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">userfuncs</span><span class="p">)</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">known_functions</span> <span class="o">=</span> <span class="n">known_functions</span> <span class="o">|</span> <span class="n">settings</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'user_functions'</span><span class="p">,</span> <span class="p">{})</span> </pre></div> </div> </section> <section id="sympy-utilities-runtests-py"> <h3><a class="toc-backref" href="#sympy-utilities-runtests-py" role="doc-backlink">sympy/utilities/runtests.py</a></h3> <p>Before:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">globs</span> <span class="o">=</span> <span class="n">globs</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="k">if</span> <span class="n">extraglobs</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="n">globs</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">extraglobs</span><span class="p">)</span> </pre></div> </div> <p>After:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">globs</span> <span class="o">=</span> <span class="n">globs</span> <span class="o">|</span> <span class="p">(</span><span class="n">extraglobs</span> <span class="k">if</span> <span class="n">extraglobs</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>The above examples show that sometimes the <code class="docutils literal notranslate"><span class="pre">|</span></code> operator leads to a clear increase in readability, reducing the number of lines of code and improving clarity. However other examples using the <code class="docutils literal notranslate"><span class="pre">|</span></code> operator lead to long, complex single expressions, possibly well over the <a class="pep reference internal" href="../pep-0008/" title="PEP 8 – Style Guide for Python Code">PEP 8</a> maximum line length of 80 columns. As with any other language feature, the programmer should use their own judgement about whether <code class="docutils literal notranslate"><span class="pre">|</span></code> improves their code.</p> </section> </section> <section id="related-discussions"> <h2><a class="toc-backref" href="#related-discussions" role="doc-backlink">Related Discussions</a></h2> <p id="discussions">Mailing list threads (this is by no means an exhaustive list):</p> <ul class="simple"> <li><a class="reference external" href="https://mail.python.org/archives/list/python-ideas@python.org/thread/BHIJX6MHGMMD3S6D7GVTPZQL4N5V7T42/">Dict joining using + and +=</a></li> <li><a class="reference external" href="https://mail.python.org/archives/list/python-ideas@python.org/thread/KLDQAPOIJEANCKYCHQZ536WHQ45I6UVW/">PEP: Dict addition and subtraction</a></li> <li><a class="reference external" href="https://mail.python.org/archives/list/python-ideas@python.org/thread/W2FCSC3JDA7NUBXAVSTVCUDEGAKWWPTH/">PEP 584: Add + and += operators to the built-in dict class.</a></li> <li><a class="reference external" href="https://mail.python.org/archives/list/python-ideas@python.org/thread/SWBLMTNQXNL3O5LN3327IYNPFIL2QSH5/">Moving PEP 584 forward (dict + and += operators)</a></li> <li><a class="reference external" href="https://mail.python.org/archives/list/python-dev@python.org/thread/TTIKCDIPC2CDHX23Y57CPHDSVYOWCCER/">PEP 584: Add Union Operators To dict</a></li> <li><a class="reference external" href="https://mail.python.org/archives/list/python-dev@python.org/thread/6KT2KIOTYXMDCD2CCAOLOI7LUGTN6MBS">Accepting PEP 584: Add Union Operators To dict</a></li> </ul> <p><a class="reference external" href="https://bugs.python.org/issue36144">Ticket on the bug tracker</a></p> <p>Merging two dictionaries in an expression is a frequently requested feature. For example:</p> <p><a class="reference external" href="https://stackoverflow.com/questions/38987/how-to-merge-two-dictionaries-in-a-single-expression">https://stackoverflow.com/questions/38987/how-to-merge-two-dictionaries-in-a-single-expression</a></p> <p><a class="reference external" href="https://stackoverflow.com/questions/1781571/how-to-concatenate-two-dictionaries-to-create-a-new-one-in-python">https://stackoverflow.com/questions/1781571/how-to-concatenate-two-dictionaries-to-create-a-new-one-in-python</a></p> <p><a class="reference external" href="https://stackoverflow.com/questions/6005066/adding-dictionaries-together-python">https://stackoverflow.com/questions/6005066/adding-dictionaries-together-python</a></p> <p>Occasionally people request alternative behavior for the merge:</p> <p><a class="reference external" href="https://stackoverflow.com/questions/1031199/adding-dictionaries-in-python">https://stackoverflow.com/questions/1031199/adding-dictionaries-in-python</a></p> <p><a class="reference external" href="https://stackoverflow.com/questions/877295/python-dict-add-by-valuedict-2">https://stackoverflow.com/questions/877295/python-dict-add-by-valuedict-2</a></p> <p>…including one proposal to treat dicts as <a class="reference external" href="https://mail.python.org/archives/list/python-ideas@python.org/message/YY3KZZGEX6VEFX5QZJ33P7NTTXGPZQ7N/">sets of keys</a>.</p> <p><a class="reference external" href="https://lwn.net/Articles/635444/">Ian Lee’s proto-PEP</a>, and <a class="reference external" href="https://lwn.net/Articles/635397/">discussion</a> in 2015. Further discussion took place on <a class="reference external" href="https://mail.python.org/archives/list/python-ideas@python.org/thread/43OZV3MR4XLFRPCI27I7BB6HVBD25M2E/">Python-Ideas</a>.</p> <p>(Observant readers will notice that one of the authors of this PEP was more skeptical of the idea in 2015.)</p> <p>Adding <a class="reference external" href="https://mail.python.org/archives/list/python-ideas@python.org/thread/EKWMDJKMVOJCOROQVHJFQX7W2L55I5RA/">a full complement of operators to dicts</a>.</p> <p><a class="reference external" href="https://news.ycombinator.com/item?id=19314646">Discussion on Y-Combinator</a>.</p> <p><a class="reference external" href="https://treyhunner.com/2016/02/how-to-merge-dictionaries-in-python/">https://treyhunner.com/2016/02/how-to-merge-dictionaries-in-python/</a></p> <p><a class="reference external" href="https://code.tutsplus.com/tutorials/how-to-merge-two-python-dictionaries--cms-26230">https://code.tutsplus.com/tutorials/how-to-merge-two-python-dictionaries–cms-26230</a></p> <p>In direct response to an earlier draft of this PEP, Serhiy Storchaka raised <a class="reference external" href="https://bugs.python.org/issue36431">a ticket in the bug tracker</a> to replace the <code class="docutils literal notranslate"><span class="pre">copy();</span> <span class="pre">update()</span></code> idiom with dict unpacking.</p> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0584.rst">https://github.com/python/peps/blob/main/peps/pep-0584.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0584.rst">2023-10-11 12:05:51 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="#motivation">Motivation</a><ul> <li><a class="reference internal" href="#dict-update"><code class="docutils literal notranslate"><span class="pre">dict.update</span></code></a></li> <li><a class="reference internal" href="#d1-d2"><code class="docutils literal notranslate"><span class="pre">{**d1,</span> <span class="pre">**d2}</span></code></a></li> <li><a class="reference internal" href="#collections-chainmap"><code class="docutils literal notranslate"><span class="pre">collections.ChainMap</span></code></a></li> <li><a class="reference internal" href="#dict-d1-d2"><code class="docutils literal notranslate"><span class="pre">dict(d1,</span> <span class="pre">**d2)</span></code></a></li> </ul> </li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#major-objections">Major Objections</a><ul> <li><a class="reference internal" href="#dict-union-is-not-commutative">Dict Union Is Not Commutative</a><ul> <li><a class="reference internal" href="#response">Response</a></li> </ul> </li> <li><a class="reference internal" href="#dict-union-will-be-inefficient">Dict Union Will Be Inefficient</a><ul> <li><a class="reference internal" href="#id1">Response</a></li> </ul> </li> <li><a class="reference internal" href="#dict-union-is-lossy">Dict Union Is Lossy</a><ul> <li><a class="reference internal" href="#id2">Response</a></li> </ul> </li> <li><a class="reference internal" href="#only-one-way-to-do-it">Only One Way To Do It</a><ul> <li><a class="reference internal" href="#id3">Response</a></li> </ul> </li> <li><a class="reference internal" href="#more-than-one-way-to-do-it">More Than One Way To Do It</a><ul> <li><a class="reference internal" href="#id4">Response</a></li> </ul> </li> <li><a class="reference internal" href="#dict-union-makes-code-harder-to-understand">Dict Union Makes Code Harder To Understand</a><ul> <li><a class="reference internal" href="#id5">Response</a></li> </ul> </li> <li><a class="reference internal" href="#what-about-the-full-set-api">What About The Full <code class="docutils literal notranslate"><span class="pre">set</span></code> API?</a><ul> <li><a class="reference internal" href="#id6">Response</a></li> </ul> </li> <li><a class="reference internal" href="#what-about-mapping-and-mutablemapping">What About <code class="docutils literal notranslate"><span class="pre">Mapping</span></code> And <code class="docutils literal notranslate"><span class="pre">MutableMapping</span></code>?</a><ul> <li><a class="reference internal" href="#id7">Response</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#rejected-semantics">Rejected Semantics</a><ul> <li><a class="reference internal" href="#raise">Raise</a></li> <li><a class="reference internal" href="#add-the-values-as-counter-does-with">Add The Values (As Counter Does, with <code class="docutils literal notranslate"><span class="pre">+</span></code>)</a></li> <li><a class="reference internal" href="#leftmost-value-first-seen-wins">Leftmost Value (First-Seen) Wins</a></li> <li><a class="reference internal" href="#concatenate-values-in-a-list">Concatenate Values In A List</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a><ul> <li><a class="reference internal" href="#use-the-addition-operator">Use The Addition Operator</a></li> <li><a class="reference internal" href="#use-the-left-shift-operator">Use The Left Shift Operator</a></li> <li><a class="reference internal" href="#use-a-new-left-arrow-operator">Use A New Left Arrow Operator</a></li> <li><a class="reference internal" href="#use-a-method">Use A Method</a><ul> <li><a class="reference internal" href="#advantages">Advantages</a></li> <li><a class="reference internal" href="#disadvantages">Disadvantages</a></li> </ul> </li> <li><a class="reference internal" href="#use-a-function">Use a Function</a><ul> <li><a class="reference internal" href="#id8">Advantages</a></li> <li><a class="reference internal" href="#id9">Disadvantages</a></li> </ul> </li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#examples">Examples</a><ul> <li><a class="reference internal" href="#ipython-zmq-ipkernel-py">IPython/zmq/ipkernel.py</a></li> <li><a class="reference internal" href="#ipython-zmq-kernelapp-py">IPython/zmq/kernelapp.py</a></li> <li><a class="reference internal" href="#matplotlib-backends-backend-svg-py">matplotlib/backends/backend_svg.py</a></li> <li><a class="reference internal" href="#matplotlib-delaunay-triangulate-py">matplotlib/delaunay/triangulate.py</a></li> <li><a class="reference internal" href="#matplotlib-legend-py">matplotlib/legend.py</a></li> <li><a class="reference internal" href="#numpy-ma-core-py">numpy/ma/core.py</a></li> <li><a class="reference internal" href="#praw-internal-py">praw/internal.py</a></li> <li><a class="reference internal" href="#pygments-lexer-py">pygments/lexer.py</a></li> <li><a class="reference internal" href="#requests-sessions-py">requests/sessions.py</a></li> <li><a class="reference internal" href="#sphinx-domains-init-py">sphinx/domains/__init__.py</a></li> <li><a class="reference internal" href="#sphinx-ext-doctest-py">sphinx/ext/doctest.py</a></li> <li><a class="reference internal" href="#sphinx-ext-inheritance-diagram-py">sphinx/ext/inheritance_diagram.py</a></li> <li><a class="reference internal" href="#sphinx-highlighting-py">sphinx/highlighting.py</a></li> <li><a class="reference internal" href="#sphinx-quickstart-py">sphinx/quickstart.py</a></li> <li><a class="reference internal" href="#sympy-abc-py">sympy/abc.py</a></li> <li><a class="reference internal" href="#sympy-parsing-maxima-py">sympy/parsing/maxima.py</a></li> <li><a class="reference internal" href="#sympy-printing-ccode-py-and-sympy-printing-fcode-py">sympy/printing/ccode.py and sympy/printing/fcode.py</a></li> <li><a class="reference internal" href="#sympy-utilities-runtests-py">sympy/utilities/runtests.py</a></li> </ul> </li> <li><a class="reference internal" href="#related-discussions">Related Discussions</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-0584.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>