python-peps/pep-0203/index.html

421 lines
36 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 203 Augmented Assignments | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0203/">
<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 203 Augmented Assignments | peps.python.org'>
<meta property="og:description" content="This PEP describes the augmented assignment proposal for Python 2.0. This PEP tracks the status and ownership of this feature, slated for introduction in Python 2.0. It contains a description of the feature and outlines changes necessary to support th...">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0203/">
<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 describes the augmented assignment proposal for Python 2.0. This PEP tracks the status and ownership of this feature, slated for introduction in Python 2.0. It contains a description of the feature and outlines changes necessary to support th...">
<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> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 203</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 203 Augmented Assignments</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Thomas Wouters &lt;thomas&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">13-Jul-2000</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.0</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">14-Aug-2000</dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#introduction">Introduction</a></li>
<li><a class="reference internal" href="#proposed-semantics">Proposed Semantics</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#new-methods">New methods</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
<li><a class="reference internal" href="#references">References</a></li>
</ul>
</details></section>
<section id="introduction">
<h2><a class="toc-backref" href="#introduction" role="doc-backlink">Introduction</a></h2>
<p>This PEP describes the <em>augmented assignment</em> proposal for Python 2.0. This
PEP tracks the status and ownership of this feature, slated for introduction
in Python 2.0. It contains a description of the feature and outlines changes
necessary to support the feature. This PEP summarizes discussions held in
mailing list forums <a class="footnote-reference brackets" href="#id3" id="id1">[1]</a>, and provides URLs for further information where
appropriate. The CVS revision history of this file contains the definitive
historical record.</p>
</section>
<section id="proposed-semantics">
<h2><a class="toc-backref" href="#proposed-semantics" role="doc-backlink">Proposed Semantics</a></h2>
<p>The proposed patch that adds augmented assignment to Python introduces the
following new operators:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">+=</span> <span class="o">-=</span> <span class="o">*=</span> <span class="o">/=</span> <span class="o">%=</span> <span class="o">**=</span> <span class="o">&lt;&lt;=</span> <span class="o">&gt;&gt;=</span> <span class="o">&amp;=</span> <span class="o">^=</span> <span class="o">|=</span>
</pre></div>
</div>
<p>They implement the same operator as their normal binary form, except that the
operation is done <em>in-place</em> when the left-hand side object supports it, and
that the left-hand side is only evaluated once.</p>
<p>They truly behave as augmented assignment, in that they perform all of the
normal load and store operations, in addition to the binary operation they are
intended to do. So, given the expression:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">+=</span> <span class="n">y</span>
</pre></div>
</div>
<p>The object <code class="docutils literal notranslate"><span class="pre">x</span></code> is loaded, then <code class="docutils literal notranslate"><span class="pre">y</span></code> is added to it, and the resulting
object is stored back in the original place. The precise action performed on
the two arguments depends on the type of <code class="docutils literal notranslate"><span class="pre">x</span></code>, and possibly of <code class="docutils literal notranslate"><span class="pre">y</span></code>.</p>
<p>The idea behind augmented assignment in Python is that it isnt just an easier
way to write the common practice of storing the result of a binary operation
in its left-hand operand, but also a way for the left-hand operand in question
to know that it should operate <em>on itself</em>, rather than creating a modified
copy of itself.</p>
<p>To make this possible, a number of new <em>hooks</em> are added to Python classes and
C extension types, which are called when the object in question is used as the
left hand side of an augmented assignment operation. If the class or type
does not implement the <em>in-place</em> hooks, the normal hooks for the particular
binary operation are used.</p>
<p>So, given an instance object <code class="docutils literal notranslate"><span class="pre">x</span></code>, the expression:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">+=</span> <span class="n">y</span>
</pre></div>
</div>
<p>tries to call <code class="docutils literal notranslate"><span class="pre">x.__iadd__(y)</span></code>, which is the <em>in-place</em> variant of
<code class="docutils literal notranslate"><span class="pre">__add__</span></code> . If <code class="docutils literal notranslate"><span class="pre">__iadd__</span></code> is not present, <code class="docutils literal notranslate"><span class="pre">x.__add__(y)</span></code> is attempted,
and finally <code class="docutils literal notranslate"><span class="pre">y.__radd__(x)</span></code> if <code class="docutils literal notranslate"><span class="pre">__add__</span></code> is missing too. There is no
<em>right-hand-side</em> variant of <code class="docutils literal notranslate"><span class="pre">__iadd__</span></code>, because that would require for
<code class="docutils literal notranslate"><span class="pre">y</span></code> to know how to in-place modify <code class="docutils literal notranslate"><span class="pre">x</span></code>, which is unsafe to say the least.
The <code class="docutils literal notranslate"><span class="pre">__iadd__</span></code> hook should behave similar to <code class="docutils literal notranslate"><span class="pre">__add__</span></code>, returning the
result of the operation (which could be <code class="docutils literal notranslate"><span class="pre">self</span></code>) which is to be assigned to
the variable <code class="docutils literal notranslate"><span class="pre">x</span></code>.</p>
<p>For C extension types, the <em>hooks</em> are members of the <code class="docutils literal notranslate"><span class="pre">PyNumberMethods</span></code> and
<code class="docutils literal notranslate"><span class="pre">PySequenceMethods</span></code> structures. Some special semantics apply to make the
use of these methods, and the mixing of Python instance objects and C types,
as unsurprising as possible.</p>
<p>In the generic case of <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">&lt;augop&gt;</span> <span class="pre">y</span></code> (or a similar case using the
<code class="docutils literal notranslate"><span class="pre">PyNumber_InPlace</span></code> API functions) the principal object being operated on is
<code class="docutils literal notranslate"><span class="pre">x</span></code>. This differs from normal binary operations, where <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code>
could be considered <em>co-operating</em>, because unlike in binary operations, the
operands in an in-place operation cannot be swapped. However, in-place
operations do fall back to normal binary operations when in-place modification
is not supported, resulting in the following rules:</p>
<ul>
<li>If the left-hand object (<code class="docutils literal notranslate"><span class="pre">x</span></code>) is an instance object, and it has a
<code class="docutils literal notranslate"><span class="pre">__coerce__</span></code> method, call that function with <code class="docutils literal notranslate"><span class="pre">y</span></code> as the argument. If
coercion succeeds, and the resulting left-hand object is a different object
than <code class="docutils literal notranslate"><span class="pre">x</span></code>, stop processing it as in-place and call the appropriate function
for the normal binary operation, with the coerced <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> as
arguments. The result of the operation is whatever that function returns.<p>If coercion does not yield a different object for <code class="docutils literal notranslate"><span class="pre">x</span></code>, or <code class="docutils literal notranslate"><span class="pre">x</span></code> does not
define a <code class="docutils literal notranslate"><span class="pre">__coerce__</span></code> method, and <code class="docutils literal notranslate"><span class="pre">x</span></code> has the appropriate <code class="docutils literal notranslate"><span class="pre">__ihook__</span></code>
for this operation, call that method with <code class="docutils literal notranslate"><span class="pre">y</span></code> as the argument, and the
result of the operation is whatever that method returns.</p>
</li>
<li>Otherwise, if the left-hand object is not an instance object, but its type
does define the in-place function for this operation, call that function
with <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> as the arguments, and the result of the operation is
whatever that function returns.<p>Note that no coercion on either <code class="docutils literal notranslate"><span class="pre">x</span></code> or <code class="docutils literal notranslate"><span class="pre">y</span></code> is done in this case, and
its perfectly valid for a C type to receive an instance object as the
second argument; that is something that cannot happen with normal binary
operations.</p>
</li>
<li>Otherwise, process it exactly as a normal binary operation (not in-place),
including argument coercion. In short, if either argument is an instance
object, resolve the operation through <code class="docutils literal notranslate"><span class="pre">__coerce__</span></code>, <code class="docutils literal notranslate"><span class="pre">__hook__</span></code> and
<code class="docutils literal notranslate"><span class="pre">__rhook__</span></code>. Otherwise, both objects are C types, and they are coerced
and passed to the appropriate function.</li>
<li>If no way to process the operation can be found, raise a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> with
an error message specific to the operation.</li>
<li>Some special casing exists to account for the case of <code class="docutils literal notranslate"><span class="pre">+</span></code> and <code class="docutils literal notranslate"><span class="pre">*</span></code>,
which have a special meaning for sequences: for <code class="docutils literal notranslate"><span class="pre">+</span></code>, sequence
concatenation, no coercion what so ever is done if a C type defines
<code class="docutils literal notranslate"><span class="pre">sq_concat</span></code> or <code class="docutils literal notranslate"><span class="pre">sq_inplace_concat</span></code>. For <code class="docutils literal notranslate"><span class="pre">*</span></code>, sequence repeating,
<code class="docutils literal notranslate"><span class="pre">y</span></code> is converted to a C integer before calling either
<code class="docutils literal notranslate"><span class="pre">sq_inplace_repeat</span></code> and <code class="docutils literal notranslate"><span class="pre">sq_repeat</span></code>. This is done even if <code class="docutils literal notranslate"><span class="pre">y</span></code> is an
instance, though not if <code class="docutils literal notranslate"><span class="pre">x</span></code> is an instance.</li>
</ul>
<p>The in-place function should always return a new reference, either to the
old <code class="docutils literal notranslate"><span class="pre">x</span></code> object if the operation was indeed performed in-place, or to a new
object.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>There are two main reasons for adding this feature to Python: simplicity of
expression, and support for in-place operations. The end result is a tradeoff
between simplicity of syntax and simplicity of expression; like most new
features, augmented assignment doesnt add anything that was previously
impossible. It merely makes these things easier to do.</p>
<p>Adding augmented assignment will make Pythons syntax more complex. Instead
of a single assignment operation, there are now twelve assignment operations,
eleven of which also perform a binary operation. However, these eleven new
forms of assignment are easy to understand as the coupling between assignment
and the binary operation, and they require no large conceptual leap to
understand. Furthermore, languages that do have augmented assignment have
shown that they are a popular, much used feature. Expressions of the form:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">x</span><span class="o">&gt;</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">x</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="n">operator</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="n">y</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>are common enough in those languages to make the extra syntax worthwhile, and
Python does not have significantly fewer of those expressions. Quite the
opposite, in fact, since in Python you can also concatenate lists with a
binary operator, something that is done quite frequently. Writing the above
expression as:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">x</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="n">operator</span><span class="o">&gt;=</span> <span class="o">&lt;</span><span class="n">y</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>is both more readable and less error prone, because it is instantly obvious to
the reader that it is <code class="docutils literal notranslate"><span class="pre">&lt;x&gt;</span></code> that is being changed, and not <code class="docutils literal notranslate"><span class="pre">&lt;x&gt;</span></code> that is
being replaced by something almost, but not quite, entirely unlike <code class="docutils literal notranslate"><span class="pre">&lt;x&gt;</span></code>.</p>
<p>The new in-place operations are especially useful to matrix calculation and
other applications that require large objects. In order to efficiently deal
with the available program memory, such packages cannot blindly use the
current binary operations. Because these operations always create a new
object, adding a single item to an existing (large) object would result in
copying the entire object (which may cause the application to run out of
memory), add the single item, and then possibly delete the original object,
depending on reference count.</p>
<p>To work around this problem, the packages currently have to use methods or
functions to modify an object in-place, which is definitely less readable than
an augmented assignment expression. Augmented assignment wont solve all the
problems for these packages, since some operations cannot be expressed in the
limited set of binary operators to start with, but it is a start. <a class="pep reference internal" href="../pep-0211/" title="PEP 211 Adding A New Outer Product Operator">PEP 211</a>
is looking at adding new operators.</p>
</section>
<section id="new-methods">
<h2><a class="toc-backref" href="#new-methods" role="doc-backlink">New methods</a></h2>
<p>The proposed implementation adds the following 11 possible <em>hooks</em> which
Python classes can implement to overload the augmented assignment operations:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="fm">__iadd__</span>
<span class="fm">__isub__</span>
<span class="fm">__imul__</span>
<span class="n">__idiv__</span>
<span class="fm">__imod__</span>
<span class="fm">__ipow__</span>
<span class="fm">__ilshift__</span>
<span class="fm">__irshift__</span>
<span class="fm">__iand__</span>
<span class="fm">__ixor__</span>
<span class="fm">__ior__</span>
</pre></div>
</div>
<p>The <em>i</em> in <code class="docutils literal notranslate"><span class="pre">__iadd__</span></code> stands for <em>in-place</em>.</p>
<p>For C extension types, the following struct members are added.</p>
<p>To <code class="docutils literal notranslate"><span class="pre">PyNumberMethods</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">binaryfunc</span> <span class="n">nb_inplace_add</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_subtract</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_multiply</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_divide</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_remainder</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_power</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_lshift</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_rshift</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_and</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_xor</span><span class="p">;</span>
<span class="n">binaryfunc</span> <span class="n">nb_inplace_or</span><span class="p">;</span>
</pre></div>
</div>
<p>To <code class="docutils literal notranslate"><span class="pre">PySequenceMethods</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">binaryfunc</span> <span class="n">sq_inplace_concat</span><span class="p">;</span>
<span class="n">intargfunc</span> <span class="n">sq_inplace_repeat</span><span class="p">;</span>
</pre></div>
</div>
<p>In order to keep binary compatibility, the <code class="docutils literal notranslate"><span class="pre">tp_flags</span></code> TypeObject member is
used to determine whether the TypeObject in question has allocated room for
these slots. Until a clean break in binary compatibility is made (which may
or may not happen before 2.0) code that wants to use one of the new struct
members must first check that they are available with the
<code class="docutils literal notranslate"><span class="pre">PyType_HasFeature()</span></code> macro:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">PyType_HasFeature</span><span class="p">(</span><span class="n">x</span><span class="o">-&gt;</span><span class="n">ob_type</span><span class="p">,</span> <span class="n">Py_TPFLAGS_HAVE_INPLACE_OPS</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
<span class="n">x</span><span class="o">-&gt;</span><span class="n">ob_type</span><span class="o">-&gt;</span><span class="n">tp_as_number</span> <span class="o">&amp;&amp;</span> <span class="n">x</span><span class="o">-&gt;</span><span class="n">ob_type</span><span class="o">-&gt;</span><span class="n">tp_as_number</span><span class="o">-&gt;</span><span class="n">nb_inplace_add</span><span class="p">)</span> <span class="p">{</span>
<span class="o">/*</span> <span class="o">...</span> <span class="o">*/</span>
</pre></div>
</div>
<p>This check must be made even before testing the method slots for <code class="docutils literal notranslate"><span class="pre">NULL</span></code>
values! The macro only tests whether the slots are available, not whether
they are filled with methods or not.</p>
</section>
<section id="implementation">
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
<p>The current implementation of augmented assignment <a class="footnote-reference brackets" href="#id4" id="id2">[2]</a> adds, in addition to
the methods and slots already covered, 13 new bytecodes and 13 new API
functions.</p>
<p>The API functions are simply in-place versions of the current binary-operation
API functions:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyNumber_InPlaceAdd</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlaceSubtract</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlaceMultiply</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlaceDivide</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlaceRemainder</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlacePower</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlaceLshift</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlaceRshift</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlaceAnd</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlaceXor</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PyNumber_InPlaceOr</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PySequence_InPlaceConcat</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o1</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">o2</span><span class="p">);</span>
<span class="n">PySequence_InPlaceRepeat</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">o</span><span class="p">,</span> <span class="nb">int</span> <span class="n">count</span><span class="p">);</span>
</pre></div>
</div>
<p>They call either the Python class hooks (if either of the objects is a Python
class instance) or the C types number or sequence methods.</p>
<p>The new bytecodes are:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">INPLACE_ADD</span>
<span class="n">INPLACE_SUBTRACT</span>
<span class="n">INPLACE_MULTIPLY</span>
<span class="n">INPLACE_DIVIDE</span>
<span class="n">INPLACE_REMAINDER</span>
<span class="n">INPLACE_POWER</span>
<span class="n">INPLACE_LEFTSHIFT</span>
<span class="n">INPLACE_RIGHTSHIFT</span>
<span class="n">INPLACE_AND</span>
<span class="n">INPLACE_XOR</span>
<span class="n">INPLACE_OR</span>
<span class="n">ROT_FOUR</span>
<span class="n">DUP_TOPX</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">INPLACE_*</span></code> bytecodes mirror the <code class="docutils literal notranslate"><span class="pre">BINARY_*</span></code> bytecodes, except that
they are implemented as calls to the <code class="docutils literal notranslate"><span class="pre">InPlace</span></code> API functions. The other two
bytecodes are <em>utility</em> bytecodes: <code class="docutils literal notranslate"><span class="pre">ROT_FOUR</span></code> behaves like <code class="docutils literal notranslate"><span class="pre">ROT_THREE</span></code>
except that the four topmost stack items are rotated.</p>
<p><code class="docutils literal notranslate"><span class="pre">DUP_TOPX</span></code> is a bytecode that takes a single argument, which should be an
integer between 1 and 5 (inclusive) which is the number of items to duplicate
in one block. Given a stack like this (where the right side of the list is
the <em>top</em> of the stack):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></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="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">DUP_TOPX</span> <span class="pre">3</span></code> would duplicate the top 3 items, resulting in this stack:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></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="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">DUP_TOPX</span></code> with an argument of 1 is the same as <code class="docutils literal notranslate"><span class="pre">DUP_TOP</span></code>. The limit of 5
is purely an implementation limit . The implementation of augmented
assignment requires only <code class="docutils literal notranslate"><span class="pre">DUP_TOPX</span></code> with an argument of 2 and 3, and could
do without this new opcode at the cost of a fair number of <code class="docutils literal notranslate"><span class="pre">DUP_TOP</span></code> and
<code class="docutils literal notranslate"><span class="pre">ROT_*</span></code>.</p>
</section>
<section id="open-issues">
<h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">PyNumber_InPlace</span></code> API is only a subset of the normal <code class="docutils literal notranslate"><span class="pre">PyNumber</span></code> API:
only those functions that are required to support the augmented assignment
syntax are included. If other in-place API functions are needed, they can be
added later.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">DUP_TOPX</span></code> bytecode is a conveniency bytecode, and is not actually
necessary. It should be considered whether this bytecode is worth having.
There seems to be no other possible use for this bytecode at this time.</p>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id3" role="doc-footnote">
<dt class="label" id="id3">[<a href="#id1">1</a>]</dt>
<dd><a class="reference external" href="http://www.python.org/pipermail/python-list/2000-June/059556.html">http://www.python.org/pipermail/python-list/2000-June/059556.html</a></aside>
<aside class="footnote brackets" id="id4" role="doc-footnote">
<dt class="label" id="id4">[<a href="#id2">2</a>]</dt>
<dd><a class="reference external" href="http://sourceforge.net/patch?func=detailpatch&amp;patch_id=100699&amp;group_id=5470">http://sourceforge.net/patch?func=detailpatch&amp;patch_id=100699&amp;group_id=5470</a></aside>
</aside>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0203.rst">https://github.com/python/peps/blob/main/peps/pep-0203.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0203.rst">2023-09-09 17:39:29 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#introduction">Introduction</a></li>
<li><a class="reference internal" href="#proposed-semantics">Proposed Semantics</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#new-methods">New methods</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
<li><a class="reference internal" href="#references">References</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0203.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>