1169 lines
106 KiB
HTML
1169 lines
106 KiB
HTML
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="color-scheme" content="light dark">
|
||
<title>PEP 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="w"> </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="w"> </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="w"> </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="w"> </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="w"> </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="w"> </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="w"> </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> |