peps/pep-0447/index.html

803 lines
99 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!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 447 Add __getdescriptor__ method to metaclass | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0447/">
<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 447 Add __getdescriptor__ method to metaclass | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0447/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 447</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 447 Add __getdescriptor__ method to metaclass</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Ronald Oussoren &lt;ronaldoussoren&#32;&#97;t&#32;mac.com&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Inactive draft that may be taken up again at a later time">Deferred</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">12-Jun-2013</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd">02-Jul-2013, 15-Jul-2013, 29-Jul-2013, 22-Jul-2015</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="#pep-status">PEP Status</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#background">Background</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-superclass-attribute-lookup-hook">The superclass attribute lookup hook</a><ul>
<li><a class="reference internal" href="#aside-attribute-resolution-algorithm-in-python">Aside: Attribute resolution algorithm in Python</a></li>
<li><a class="reference internal" href="#in-python-code">In Python code</a><ul>
<li><a class="reference internal" href="#example-usage">Example usage</a></li>
</ul>
</li>
<li><a class="reference internal" href="#in-c-code">In C code</a></li>
<li><a class="reference internal" href="#use-of-this-hook-by-the-interpreter">Use of this hook by the interpreter</a></li>
<li><a class="reference internal" href="#other-changes-to-the-implementation">Other changes to the implementation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#impact-of-this-pep-on-introspection">Impact of this PEP on introspection</a></li>
<li><a class="reference internal" href="#performance-impact">Performance impact</a><ul>
<li><a class="reference internal" href="#micro-benchmarks">Micro benchmarks</a></li>
<li><a class="reference internal" href="#pybench">Pybench</a></li>
</ul>
</li>
<li><a class="reference internal" href="#alternative-proposals">Alternative proposals</a><ul>
<li><a class="reference internal" href="#getattribute-super"><code class="docutils literal notranslate"><span class="pre">__getattribute_super__</span></code></a></li>
<li><a class="reference internal" href="#reuse-tp-getattro">Reuse <code class="docutils literal notranslate"><span class="pre">tp_getattro</span></code></a></li>
<li><a class="reference internal" href="#alternative-placement-of-the-new-method">Alternative placement of the new method</a></li>
</ul>
</li>
<li><a class="reference internal" href="#history">History</a></li>
<li><a class="reference internal" href="#discussion-threads">Discussion threads</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>Currently <code class="docutils literal notranslate"><span class="pre">object.__getattribute__</span></code> and <code class="docutils literal notranslate"><span class="pre">super.__getattribute__</span></code> peek
in the <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> of classes on the MRO for a class when looking for
an attribute. This PEP adds an optional <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method to
a metaclass that replaces this behavior and gives more control over attribute
lookup, especially when using a <a class="reference external" href="http://docs.python.org/3/library/functions.html#super">super</a> object.</p>
<p>That is, the MRO walking loop in <code class="docutils literal notranslate"><span class="pre">_PyType_Lookup</span></code> and
<code class="docutils literal notranslate"><span class="pre">super.__getattribute__</span></code> gets changed from:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">lookup</span><span class="p">(</span><span class="n">mro_list</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="n">mro_list</span><span class="p">:</span>
<span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span>
<span class="k">return</span> <span class="n">NotFound</span>
</pre></div>
</div>
<p>to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">lookup</span><span class="p">(</span><span class="n">mro_list</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="n">mro_list</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">__getdescriptor__</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">return</span> <span class="n">NotFound</span>
</pre></div>
</div>
<p>The default implementation of <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> looks in the class
dictionary:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">type</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">__getdescriptor__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="kn">from</span> <span class="kc">None</span>
</pre></div>
</div>
</section>
<section id="pep-status">
<h2><a class="toc-backref" href="#pep-status" role="doc-backlink">PEP Status</a></h2>
<p>This PEP is deferred until someone has time to update this PEP and push it forward.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>It is currently not possible to influence how the <a class="reference external" href="http://docs.python.org/3/library/functions.html#super">super class</a> looks
up attributes (that is, <code class="docutils literal notranslate"><span class="pre">super.__getattribute__</span></code> unconditionally
peeks in the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>), and that can be problematic for
dynamic classes that can grow new methods on demand, for example dynamic
proxy classes.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method makes it possible to dynamically add
attributes even when looking them up using the <a class="reference external" href="http://docs.python.org/3/library/functions.html#super">super class</a>.</p>
<p>The new method affects <code class="docutils literal notranslate"><span class="pre">object.__getattribute__</span></code> (and
<a class="reference external" href="http://docs.python.org/3/c-api/object.html#PyObject_GenericGetAttr">PyObject_GenericGetAttr</a>) as well for consistency and to have a single
place to implement dynamic attribute resolution for classes.</p>
<section id="background">
<h3><a class="toc-backref" href="#background" role="doc-backlink">Background</a></h3>
<p>The current behavior of <code class="docutils literal notranslate"><span class="pre">super.__getattribute__</span></code> causes problems for
classes that are dynamic proxies for other (non-Python) classes or types,
an example of which is <a class="reference external" href="http://pyobjc.sourceforge.net/">PyObjC</a>. PyObjC creates a Python class for every
class in the Objective-C runtime, and looks up methods in the Objective-C
runtime when they are used. This works fine for normal access, but doesnt
work for access with <a class="reference external" href="http://docs.python.org/3/library/functions.html#super">super</a> objects. Because of this PyObjC currently
includes a custom <a class="reference external" href="http://docs.python.org/3/library/functions.html#super">super</a> that must be used with its classes, as well as
completely reimplementing <a class="reference external" href="http://docs.python.org/3/c-api/object.html#PyObject_GenericGetAttr">PyObject_GenericGetAttr</a> for normal attribute
access.</p>
<p>The API in this PEP makes it possible to remove the custom <a class="reference external" href="http://docs.python.org/3/library/functions.html#super">super</a> and
simplifies the implementation because the custom lookup behavior can be
added in a central location.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p><a class="reference external" href="http://pyobjc.sourceforge.net/">PyObjC</a> cannot precalculate the contents of the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>
because Objective-C classes can grow new methods at runtime. Furthermore,
Objective-C classes tend to contain a lot of methods while most Python
code will only use a small subset of them, this makes precalculating
unnecessarily expensive.</p>
</div>
</section>
</section>
<section id="the-superclass-attribute-lookup-hook">
<h2><a class="toc-backref" href="#the-superclass-attribute-lookup-hook" role="doc-backlink">The superclass attribute lookup hook</a></h2>
<p>Both <code class="docutils literal notranslate"><span class="pre">super.__getattribute__</span></code> and <code class="docutils literal notranslate"><span class="pre">object.__getattribute__</span></code> (or
<a class="reference external" href="http://docs.python.org/3/c-api/object.html#PyObject_GenericGetAttr">PyObject_GenericGetAttr</a> and in particular <code class="docutils literal notranslate"><span class="pre">_PyType_Lookup</span></code> in C code)
walk an objects MRO and currently peek in the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> to look up
attributes.</p>
<p>With this proposal both lookup methods no longer peek in the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>
but call the special method <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code>, which is a slot defined
on the metaclass. The default implementation of that method looks
up the name the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>, which means that attribute lookup is
unchanged unless a metatype actually defines the new special method.</p>
<section id="aside-attribute-resolution-algorithm-in-python">
<h3><a class="toc-backref" href="#aside-attribute-resolution-algorithm-in-python" role="doc-backlink">Aside: Attribute resolution algorithm in Python</a></h3>
<p>The attribute resolution process as implemented by <code class="docutils literal notranslate"><span class="pre">object.__getattribute__</span></code>
(or <code class="docutils literal notranslate"><span class="pre">PyObject_GenericGetAttr</span></code> in CPythons implementation) is fairly
straightforward, but not entirely so without reading C code.</p>
<p>The current CPython implementation of object.__getattribute__ is basically
equivalent to the following (pseudo-) Python code (excluding some house
keeping and speed tricks):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">_PyType_Lookup</span><span class="p">(</span><span class="n">tp</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="n">mro</span> <span class="o">=</span> <span class="n">tp</span><span class="o">.</span><span class="n">mro</span><span class="p">()</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">mro</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">)</span>
<span class="k">for</span> <span class="n">base</span> <span class="ow">in</span> <span class="n">mro</span><span class="p">:</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="nb">type</span><span class="p">)</span>
<span class="c1"># PEP 447 will change these lines:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">base</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">class</span> <span class="nc">object</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__getattribute__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
<span class="n">tp</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="n">descr</span> <span class="o">=</span> <span class="n">_PyType_Lookup</span><span class="p">(</span><span class="n">tp</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
<span class="n">f</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">descr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">descr</span><span class="o">.</span><span class="fm">__get__</span>
<span class="k">if</span> <span class="n">f</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">descr</span><span class="o">.</span><span class="fm">__set__</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># Data descriptor</span>
<span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="n">descr</span><span class="p">,</span> <span class="bp">self</span><span class="p">,</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>
<span class="nb">dict</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span>
<span class="k">if</span> <span class="nb">dict</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">if</span> <span class="n">f</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># Non-data descriptor</span>
<span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="n">descr</span><span class="p">,</span> <span class="bp">self</span><span class="p">,</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">))</span>
<span class="k">if</span> <span class="n">descr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># Regular class attribute</span>
<span class="k">return</span> <span class="n">descr</span>
<span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">super</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__getattribute__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">unicode</span><span class="p">)</span>
<span class="k">if</span> <span class="n">name</span> <span class="o">!=</span> <span class="s1">&#39;__class__&#39;</span><span class="p">:</span>
<span class="n">starttype</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__self_type__</span>
<span class="n">mro</span> <span class="o">=</span> <span class="n">startype</span><span class="o">.</span><span class="n">mro</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">idx</span> <span class="o">=</span> <span class="n">mro</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__thisclass__</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">for</span> <span class="n">base</span> <span class="ow">in</span> <span class="n">mro</span><span class="p">[</span><span class="n">idx</span><span class="o">+</span><span class="mi">1</span><span class="p">:]:</span>
<span class="c1"># PEP 447 will change these lines:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">descr</span> <span class="o">=</span> <span class="n">base</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">continue</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">descr</span><span class="o">.</span><span class="fm">__get__</span>
<span class="k">if</span> <span class="n">f</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="n">descr</span><span class="p">,</span>
<span class="kc">None</span> <span class="k">if</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="vm">__self__</span> <span class="ow">is</span> <span class="bp">self</span><span class="o">.</span><span class="n">__self_type__</span><span class="p">)</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__self__</span><span class="p">,</span>
<span class="n">starttype</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">descr</span>
<span class="k">return</span> <span class="nb">object</span><span class="o">.</span><span class="fm">__getattribute__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
</pre></div>
</div>
<p>This PEP should change the dict lookup at the lines starting at “# PEP 447” with
a method call to perform the actual lookup, making is possible to affect that
lookup both for normal attribute access and access through the <a class="reference external" href="http://docs.python.org/3/library/functions.html#super">super proxy</a>.</p>
<p>Note that specific classes can already completely override the default
behaviour by implementing their own <code class="docutils literal notranslate"><span class="pre">__getattribute__</span></code> slot (with or without
calling the super class implementation).</p>
</section>
<section id="in-python-code">
<h3><a class="toc-backref" href="#in-python-code" role="doc-backlink">In Python code</a></h3>
<p>A meta type can define a method <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> that is called during
attribute resolution by both <code class="docutils literal notranslate"><span class="pre">super.__getattribute__</span></code>
and <code class="docutils literal notranslate"><span class="pre">object.__getattribute</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MetaType</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__getdescriptor__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="kn">from</span> <span class="kc">None</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method has as its arguments a class (which is an
instance of the meta type) and the name of the attribute that is looked up.
It should return the value of the attribute without invoking descriptors,
and should raise <a class="reference external" href="http://docs.python.org/3/library/exceptions.html#AttributeError">AttributeError</a> when the name cannot be found.</p>
<p>The <a class="reference external" href="http://docs.python.org/3/library/functions.html#type">type</a> class provides a default implementation for <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code>,
that looks up the name in the class dictionary.</p>
<section id="example-usage">
<h4><a class="toc-backref" href="#example-usage" role="doc-backlink">Example usage</a></h4>
<p>The code below implements a silly metaclass that redirects attribute lookup to
uppercase versions of names:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">UpperCaseAccess</span> <span class="p">(</span><span class="nb">type</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__getdescriptor__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">name</span><span class="o">.</span><span class="n">upper</span><span class="p">()]</span>
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="kn">from</span> <span class="kc">None</span>
<span class="k">class</span> <span class="nc">SillyObject</span> <span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">UpperCaseAccess</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">m</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="mi">42</span>
<span class="k">def</span> <span class="nf">M</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">&quot;fortytwo&quot;</span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">SillyObject</span><span class="p">()</span>
<span class="k">assert</span> <span class="n">obj</span><span class="o">.</span><span class="n">m</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&quot;fortytwo&quot;</span>
</pre></div>
</div>
<p>As mentioned earlier in this PEP a more realistic use case of this
functionality is a <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method that dynamically populates the
class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> based on attribute access, primarily when it is not
possible to reliably keep the class dict in sync with its source, for example
because the source used to populate <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> is dynamic as well and does
not have triggers that can be used to detect changes to that source.</p>
<p>An example of that are the class bridges in PyObjC: the class bridge is a
Python object (class) that represents an Objective-C class and conceptually
has a Python method for every Objective-C method in the Objective-C class.
As with Python it is possible to add new methods to an Objective-C class, or
replace existing ones, and there are no callbacks that can be used to detect
this.</p>
</section>
</section>
<section id="in-c-code">
<h3><a class="toc-backref" href="#in-c-code" role="doc-backlink">In C code</a></h3>
<p>A new type flag <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_GETDESCRIPTOR</span></code> with value <code class="docutils literal notranslate"><span class="pre">(1UL</span> <span class="pre">&lt;&lt;</span> <span class="pre">11)</span></code> that
indicates that the new slot is present and to be used.</p>
<p>A new slot <code class="docutils literal notranslate"><span class="pre">tp_getdescriptor</span></code> is added to the <code class="docutils literal notranslate"><span class="pre">PyTypeObject</span></code> struct, this
slot corresponds to the <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method on <a class="reference external" href="http://docs.python.org/3/library/functions.html#type">type</a>.</p>
<p>The slot has the following prototype:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="o">*</span> <span class="p">(</span><span class="o">*</span><span class="n">getdescriptorfunc</span><span class="p">)(</span><span class="n">PyTypeObject</span><span class="o">*</span> <span class="bp">cls</span><span class="p">,</span> <span class="n">PyObject</span><span class="o">*</span> <span class="n">name</span><span class="p">);</span>
</pre></div>
</div>
<p>This method should lookup <em>name</em> in the namespace of <em>cls</em>, without looking at
superclasses, and should not invoke descriptors. The method returns <code class="docutils literal notranslate"><span class="pre">NULL</span></code>
without setting an exception when the <em>name</em> cannot be found, and returns a
new reference otherwise (not a borrowed reference).</p>
<p>Classes with a <code class="docutils literal notranslate"><span class="pre">tp_getdescriptor</span></code> slot must add <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_GETDESCRIPTOR</span></code>
to <code class="docutils literal notranslate"><span class="pre">tp_flags</span></code> to indicate that new slot must be used.</p>
</section>
<section id="use-of-this-hook-by-the-interpreter">
<h3><a class="toc-backref" href="#use-of-this-hook-by-the-interpreter" role="doc-backlink">Use of this hook by the interpreter</a></h3>
<p>The new method is required for metatypes and as such is defined on <code class="docutils literal notranslate"><span class="pre">type_</span></code>.
Both <code class="docutils literal notranslate"><span class="pre">super.__getattribute__</span></code> and
<code class="docutils literal notranslate"><span class="pre">object.__getattribute__</span></code>/<a class="reference external" href="http://docs.python.org/3/c-api/object.html#PyObject_GenericGetAttr">PyObject_GenericGetAttr</a>
(through <code class="docutils literal notranslate"><span class="pre">_PyType_Lookup</span></code>) use the this <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method when
walking the MRO.</p>
</section>
<section id="other-changes-to-the-implementation">
<h3><a class="toc-backref" href="#other-changes-to-the-implementation" role="doc-backlink">Other changes to the implementation</a></h3>
<p>The change for <a class="reference external" href="http://docs.python.org/3/c-api/object.html#PyObject_GenericGetAttr">PyObject_GenericGetAttr</a> will be done by changing the private
function <code class="docutils literal notranslate"><span class="pre">_PyType_Lookup</span></code>. This currently returns a borrowed reference, but
must return a new reference when the <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method is present.
Because of this <code class="docutils literal notranslate"><span class="pre">_PyType_Lookup</span></code> will be renamed to <code class="docutils literal notranslate"><span class="pre">_PyType_LookupName</span></code>,
this will cause compile-time errors for all out-of-tree users of this
private API.</p>
<p>For the same reason <code class="docutils literal notranslate"><span class="pre">_PyType_LookupId</span></code> is renamed to <code class="docutils literal notranslate"><span class="pre">_PyType_LookupId2</span></code>.
A number of other functions in typeobject.c with the same issue do not get
an updated name because they are private to that file.</p>
<p>The attribute lookup cache in <code class="docutils literal notranslate"><span class="pre">Objects/typeobject.c</span></code> is disabled for classes
that have a metaclass that overrides <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code>, because using the
cache might not be valid for such classes.</p>
</section>
</section>
<section id="impact-of-this-pep-on-introspection">
<h2><a class="toc-backref" href="#impact-of-this-pep-on-introspection" role="doc-backlink">Impact of this PEP on introspection</a></h2>
<p>Use of the method introduced in this PEP can affect introspection of classes
with a metaclass that uses a custom <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method. This section
lists those changes.</p>
<p>The items listed below are only affected by custom <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code>
methods, the default implementation for <code class="docutils literal notranslate"><span class="pre">object</span></code> wont cause problems
because that still only uses the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> and wont cause visible
changes to the visible behaviour of the <code class="docutils literal notranslate"><span class="pre">object.__getattribute__</span></code>.</p>
<ul>
<li><code class="docutils literal notranslate"><span class="pre">dir</span></code> might not show all attributes<p>As with a custom <code class="docutils literal notranslate"><span class="pre">__getattribute__</span></code> method <a class="reference external" href="http://docs.python.org/3/library/functions.html#dir">dir()</a> might not see all
(instance) attributes when using the <code class="docutils literal notranslate"><span class="pre">__getdescriptor__()</span></code> method to
dynamically resolve attributes.</p>
<p>The solution for that is quite simple: classes using <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code>
should also implement <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#object.__dir__">__dir__()</a> if they want full support for the builtin
<a class="reference external" href="http://docs.python.org/3/library/functions.html#dir">dir()</a> function.</p>
</li>
<li><code class="docutils literal notranslate"><span class="pre">inspect.getattr_static</span></code> might not show all attributes<p>The function <code class="docutils literal notranslate"><span class="pre">inspect.getattr_static</span></code> intentionally does not invoke
<code class="docutils literal notranslate"><span class="pre">__getattribute__</span></code> and descriptors to avoid invoking user code during
introspection with this function. The <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method will also
be ignored and is another way in which the result of <code class="docutils literal notranslate"><span class="pre">inspect.getattr_static</span></code>
can be different from that of <code class="docutils literal notranslate"><span class="pre">builtin.getattr</span></code>.</p>
</li>
<li><code class="docutils literal notranslate"><span class="pre">inspect.getmembers</span></code> and <code class="docutils literal notranslate"><span class="pre">inspect.classify_class_attrs</span></code><p>Both of these functions directly access the class __dict__ of classes along
the MRO, and hence can be affected by a custom <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method.</p>
<p>Code with a custom <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method that want to play nice with
these methods also needs to ensure that the <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> is set up correctly
when that is accessed directly by Python code.</p>
<p>Note that <code class="docutils literal notranslate"><span class="pre">inspect.getmembers</span></code> is used by <code class="docutils literal notranslate"><span class="pre">pydoc</span></code> and hence this can
affect runtime documentation introspection.</p>
</li>
<li>Direct introspection of the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code><p>Any code that directly access the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> for introspection
can be affected by a custom <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method, see the previous
item.</p>
</li>
</ul>
</section>
<section id="performance-impact">
<h2><a class="toc-backref" href="#performance-impact" role="doc-backlink">Performance impact</a></h2>
<p><strong>WARNING</strong>: The benchmark results in this section are old, and will be updated
when Ive ported the patch to the current trunk. I dont expect significant
changes to the results in this section.</p>
<section id="micro-benchmarks">
<h3><a class="toc-backref" href="#micro-benchmarks" role="doc-backlink">Micro benchmarks</a></h3>
<p><a class="reference external" href="http://bugs.python.org/issue18181">Issue 18181</a> has a micro benchmark as one of its attachments
(<a class="reference external" href="http://bugs.python.org/file40013/pep447-micro-bench.py">pep447-micro-bench.py</a>) that specifically tests the speed of attribute
lookup, both directly and through super.</p>
<p>Note that attribute lookup with deep class hierarchies is significantly slower
when using a custom <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> method. This is because the
attribute lookup cache for CPython cannot be used when having this method.</p>
</section>
<section id="pybench">
<h3><a class="toc-backref" href="#pybench" role="doc-backlink">Pybench</a></h3>
<p>The pybench output below compares an implementation of this PEP with the
regular source tree, both based on changeset a5681f50bae2, run on an idle
machine and Core i7 processor running Centos 6.4.</p>
<p>Even though the machine was idle there were clear differences between runs,
Ive seen difference in “minimum time” vary from -0.1% to +1.5%, with similar
(but slightly smaller) differences in the “average time” difference.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">-------------------------------------------------------------------------------</span>
<span class="n">PYBENCH</span> <span class="mf">2.1</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="o">*</span> <span class="n">using</span> <span class="n">CPython</span> <span class="mf">3.4.0</span><span class="n">a0</span> <span class="p">(</span><span class="n">default</span><span class="p">,</span> <span class="n">Jul</span> <span class="mi">29</span> <span class="mi">2013</span><span class="p">,</span> <span class="mi">13</span><span class="p">:</span><span class="mi">01</span><span class="p">:</span><span class="mi">34</span><span class="p">)</span> <span class="p">[</span><span class="n">GCC</span> <span class="mf">4.4.7</span> <span class="mi">20120313</span> <span class="p">(</span><span class="n">Red</span> <span class="n">Hat</span> <span class="mf">4.4.7</span><span class="o">-</span><span class="mi">3</span><span class="p">)]</span>
<span class="o">*</span> <span class="n">disabled</span> <span class="n">garbage</span> <span class="n">collection</span>
<span class="o">*</span> <span class="n">system</span> <span class="n">check</span> <span class="n">interval</span> <span class="nb">set</span> <span class="n">to</span> <span class="n">maximum</span><span class="p">:</span> <span class="mi">2147483647</span>
<span class="o">*</span> <span class="n">using</span> <span class="n">timer</span><span class="p">:</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span>
<span class="o">*</span> <span class="n">timer</span><span class="p">:</span> <span class="n">resolution</span><span class="o">=</span><span class="mf">1e-09</span><span class="p">,</span> <span class="n">implementation</span><span class="o">=</span><span class="n">clock_gettime</span><span class="p">(</span><span class="n">CLOCK_MONOTONIC</span><span class="p">)</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">Benchmark</span><span class="p">:</span> <span class="n">pep447</span><span class="o">.</span><span class="n">pybench</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">Rounds</span><span class="p">:</span> <span class="mi">10</span>
<span class="n">Warp</span><span class="p">:</span> <span class="mi">10</span>
<span class="n">Timer</span><span class="p">:</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span>
<span class="n">Machine</span> <span class="n">Details</span><span class="p">:</span>
<span class="n">Platform</span> <span class="n">ID</span><span class="p">:</span> <span class="n">Linux</span><span class="o">-</span><span class="mf">2.6.32</span><span class="o">-</span><span class="mf">358.114.1</span><span class="o">.</span><span class="n">openstack</span><span class="o">.</span><span class="n">el6</span><span class="o">.</span><span class="n">x86_64</span><span class="o">-</span><span class="n">x86_64</span><span class="o">-</span><span class="k">with</span><span class="o">-</span><span class="n">centos</span><span class="o">-</span><span class="mf">6.4</span><span class="o">-</span><span class="n">Final</span>
<span class="n">Processor</span><span class="p">:</span> <span class="n">x86_64</span>
<span class="n">Python</span><span class="p">:</span>
<span class="n">Implementation</span><span class="p">:</span> <span class="n">CPython</span>
<span class="n">Executable</span><span class="p">:</span> <span class="o">/</span><span class="n">tmp</span><span class="o">/</span><span class="n">default</span><span class="o">-</span><span class="n">pep447</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">python3</span>
<span class="n">Version</span><span class="p">:</span> <span class="mf">3.4.0</span><span class="n">a0</span>
<span class="n">Compiler</span><span class="p">:</span> <span class="n">GCC</span> <span class="mf">4.4.7</span> <span class="mi">20120313</span> <span class="p">(</span><span class="n">Red</span> <span class="n">Hat</span> <span class="mf">4.4.7</span><span class="o">-</span><span class="mi">3</span><span class="p">)</span>
<span class="n">Bits</span><span class="p">:</span> <span class="mi">64</span><span class="n">bit</span>
<span class="n">Build</span><span class="p">:</span> <span class="n">Jul</span> <span class="mi">29</span> <span class="mi">2013</span> <span class="mi">14</span><span class="p">:</span><span class="mi">09</span><span class="p">:</span><span class="mi">12</span> <span class="p">(</span><span class="c1">#default)</span>
<span class="n">Unicode</span><span class="p">:</span> <span class="n">UCS4</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">Comparing</span> <span class="k">with</span><span class="p">:</span> <span class="n">default</span><span class="o">.</span><span class="n">pybench</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">Rounds</span><span class="p">:</span> <span class="mi">10</span>
<span class="n">Warp</span><span class="p">:</span> <span class="mi">10</span>
<span class="n">Timer</span><span class="p">:</span> <span class="n">time</span><span class="o">.</span><span class="n">perf_counter</span>
<span class="n">Machine</span> <span class="n">Details</span><span class="p">:</span>
<span class="n">Platform</span> <span class="n">ID</span><span class="p">:</span> <span class="n">Linux</span><span class="o">-</span><span class="mf">2.6.32</span><span class="o">-</span><span class="mf">358.114.1</span><span class="o">.</span><span class="n">openstack</span><span class="o">.</span><span class="n">el6</span><span class="o">.</span><span class="n">x86_64</span><span class="o">-</span><span class="n">x86_64</span><span class="o">-</span><span class="k">with</span><span class="o">-</span><span class="n">centos</span><span class="o">-</span><span class="mf">6.4</span><span class="o">-</span><span class="n">Final</span>
<span class="n">Processor</span><span class="p">:</span> <span class="n">x86_64</span>
<span class="n">Python</span><span class="p">:</span>
<span class="n">Implementation</span><span class="p">:</span> <span class="n">CPython</span>
<span class="n">Executable</span><span class="p">:</span> <span class="o">/</span><span class="n">tmp</span><span class="o">/</span><span class="n">default</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">python3</span>
<span class="n">Version</span><span class="p">:</span> <span class="mf">3.4.0</span><span class="n">a0</span>
<span class="n">Compiler</span><span class="p">:</span> <span class="n">GCC</span> <span class="mf">4.4.7</span> <span class="mi">20120313</span> <span class="p">(</span><span class="n">Red</span> <span class="n">Hat</span> <span class="mf">4.4.7</span><span class="o">-</span><span class="mi">3</span><span class="p">)</span>
<span class="n">Bits</span><span class="p">:</span> <span class="mi">64</span><span class="n">bit</span>
<span class="n">Build</span><span class="p">:</span> <span class="n">Jul</span> <span class="mi">29</span> <span class="mi">2013</span> <span class="mi">13</span><span class="p">:</span><span class="mi">01</span><span class="p">:</span><span class="mi">34</span> <span class="p">(</span><span class="c1">#default)</span>
<span class="n">Unicode</span><span class="p">:</span> <span class="n">UCS4</span>
<span class="n">Test</span> <span class="n">minimum</span> <span class="n">run</span><span class="o">-</span><span class="n">time</span> <span class="n">average</span> <span class="n">run</span><span class="o">-</span><span class="n">time</span>
<span class="n">this</span> <span class="n">other</span> <span class="n">diff</span> <span class="n">this</span> <span class="n">other</span> <span class="n">diff</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">BuiltinFunctionCalls</span><span class="p">:</span> <span class="mi">45</span><span class="n">ms</span> <span class="mi">44</span><span class="n">ms</span> <span class="o">+</span><span class="mf">1.3</span><span class="o">%</span> <span class="mi">45</span><span class="n">ms</span> <span class="mi">44</span><span class="n">ms</span> <span class="o">+</span><span class="mf">1.3</span><span class="o">%</span>
<span class="n">BuiltinMethodLookup</span><span class="p">:</span> <span class="mi">26</span><span class="n">ms</span> <span class="mi">27</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.4</span><span class="o">%</span> <span class="mi">27</span><span class="n">ms</span> <span class="mi">27</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.2</span><span class="o">%</span>
<span class="n">CompareFloats</span><span class="p">:</span> <span class="mi">33</span><span class="n">ms</span> <span class="mi">34</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.7</span><span class="o">%</span> <span class="mi">33</span><span class="n">ms</span> <span class="mi">34</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.1</span><span class="o">%</span>
<span class="n">CompareFloatsIntegers</span><span class="p">:</span> <span class="mi">66</span><span class="n">ms</span> <span class="mi">67</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.9</span><span class="o">%</span> <span class="mi">66</span><span class="n">ms</span> <span class="mi">67</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.8</span><span class="o">%</span>
<span class="n">CompareIntegers</span><span class="p">:</span> <span class="mi">51</span><span class="n">ms</span> <span class="mi">50</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.9</span><span class="o">%</span> <span class="mi">51</span><span class="n">ms</span> <span class="mi">50</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.8</span><span class="o">%</span>
<span class="n">CompareInternedStrings</span><span class="p">:</span> <span class="mi">34</span><span class="n">ms</span> <span class="mi">33</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.4</span><span class="o">%</span> <span class="mi">34</span><span class="n">ms</span> <span class="mi">34</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.4</span><span class="o">%</span>
<span class="n">CompareLongs</span><span class="p">:</span> <span class="mi">29</span><span class="n">ms</span> <span class="mi">29</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.1</span><span class="o">%</span> <span class="mi">29</span><span class="n">ms</span> <span class="mi">29</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.0</span><span class="o">%</span>
<span class="n">CompareStrings</span><span class="p">:</span> <span class="mi">43</span><span class="n">ms</span> <span class="mi">44</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.8</span><span class="o">%</span> <span class="mi">44</span><span class="n">ms</span> <span class="mi">44</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.8</span><span class="o">%</span>
<span class="n">ComplexPythonFunctionCalls</span><span class="p">:</span> <span class="mi">44</span><span class="n">ms</span> <span class="mi">42</span><span class="n">ms</span> <span class="o">+</span><span class="mf">3.9</span><span class="o">%</span> <span class="mi">44</span><span class="n">ms</span> <span class="mi">42</span><span class="n">ms</span> <span class="o">+</span><span class="mf">4.1</span><span class="o">%</span>
<span class="n">ConcatStrings</span><span class="p">:</span> <span class="mi">33</span><span class="n">ms</span> <span class="mi">33</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.4</span><span class="o">%</span> <span class="mi">33</span><span class="n">ms</span> <span class="mi">33</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.0</span><span class="o">%</span>
<span class="n">CreateInstances</span><span class="p">:</span> <span class="mi">47</span><span class="n">ms</span> <span class="mi">48</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.9</span><span class="o">%</span> <span class="mi">47</span><span class="n">ms</span> <span class="mi">49</span><span class="n">ms</span> <span class="o">-</span><span class="mf">3.4</span><span class="o">%</span>
<span class="n">CreateNewInstances</span><span class="p">:</span> <span class="mi">35</span><span class="n">ms</span> <span class="mi">36</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.5</span><span class="o">%</span> <span class="mi">36</span><span class="n">ms</span> <span class="mi">36</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.5</span><span class="o">%</span>
<span class="n">CreateStringsWithConcat</span><span class="p">:</span> <span class="mi">69</span><span class="n">ms</span> <span class="mi">70</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.7</span><span class="o">%</span> <span class="mi">69</span><span class="n">ms</span> <span class="mi">70</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.9</span><span class="o">%</span>
<span class="n">DictCreation</span><span class="p">:</span> <span class="mi">52</span><span class="n">ms</span> <span class="mi">50</span><span class="n">ms</span> <span class="o">+</span><span class="mf">3.1</span><span class="o">%</span> <span class="mi">52</span><span class="n">ms</span> <span class="mi">50</span><span class="n">ms</span> <span class="o">+</span><span class="mf">3.0</span><span class="o">%</span>
<span class="n">DictWithFloatKeys</span><span class="p">:</span> <span class="mi">40</span><span class="n">ms</span> <span class="mi">44</span><span class="n">ms</span> <span class="o">-</span><span class="mf">10.1</span><span class="o">%</span> <span class="mi">43</span><span class="n">ms</span> <span class="mi">45</span><span class="n">ms</span> <span class="o">-</span><span class="mf">5.8</span><span class="o">%</span>
<span class="n">DictWithIntegerKeys</span><span class="p">:</span> <span class="mi">32</span><span class="n">ms</span> <span class="mi">36</span><span class="n">ms</span> <span class="o">-</span><span class="mf">11.2</span><span class="o">%</span> <span class="mi">35</span><span class="n">ms</span> <span class="mi">37</span><span class="n">ms</span> <span class="o">-</span><span class="mf">4.6</span><span class="o">%</span>
<span class="n">DictWithStringKeys</span><span class="p">:</span> <span class="mi">29</span><span class="n">ms</span> <span class="mi">34</span><span class="n">ms</span> <span class="o">-</span><span class="mf">15.7</span><span class="o">%</span> <span class="mi">35</span><span class="n">ms</span> <span class="mi">40</span><span class="n">ms</span> <span class="o">-</span><span class="mf">11.0</span><span class="o">%</span>
<span class="n">ForLoops</span><span class="p">:</span> <span class="mi">30</span><span class="n">ms</span> <span class="mi">29</span><span class="n">ms</span> <span class="o">+</span><span class="mf">2.2</span><span class="o">%</span> <span class="mi">30</span><span class="n">ms</span> <span class="mi">29</span><span class="n">ms</span> <span class="o">+</span><span class="mf">2.2</span><span class="o">%</span>
<span class="n">IfThenElse</span><span class="p">:</span> <span class="mi">38</span><span class="n">ms</span> <span class="mi">41</span><span class="n">ms</span> <span class="o">-</span><span class="mf">6.7</span><span class="o">%</span> <span class="mi">38</span><span class="n">ms</span> <span class="mi">41</span><span class="n">ms</span> <span class="o">-</span><span class="mf">6.9</span><span class="o">%</span>
<span class="n">ListSlicing</span><span class="p">:</span> <span class="mi">36</span><span class="n">ms</span> <span class="mi">36</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.7</span><span class="o">%</span> <span class="mi">36</span><span class="n">ms</span> <span class="mi">37</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.3</span><span class="o">%</span>
<span class="n">NestedForLoops</span><span class="p">:</span> <span class="mi">43</span><span class="n">ms</span> <span class="mi">45</span><span class="n">ms</span> <span class="o">-</span><span class="mf">3.1</span><span class="o">%</span> <span class="mi">43</span><span class="n">ms</span> <span class="mi">45</span><span class="n">ms</span> <span class="o">-</span><span class="mf">3.2</span><span class="o">%</span>
<span class="n">NestedListComprehensions</span><span class="p">:</span> <span class="mi">39</span><span class="n">ms</span> <span class="mi">40</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.7</span><span class="o">%</span> <span class="mi">39</span><span class="n">ms</span> <span class="mi">40</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.1</span><span class="o">%</span>
<span class="n">NormalClassAttribute</span><span class="p">:</span> <span class="mi">86</span><span class="n">ms</span> <span class="mi">82</span><span class="n">ms</span> <span class="o">+</span><span class="mf">5.1</span><span class="o">%</span> <span class="mi">86</span><span class="n">ms</span> <span class="mi">82</span><span class="n">ms</span> <span class="o">+</span><span class="mf">5.0</span><span class="o">%</span>
<span class="n">NormalInstanceAttribute</span><span class="p">:</span> <span class="mi">42</span><span class="n">ms</span> <span class="mi">42</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.3</span><span class="o">%</span> <span class="mi">42</span><span class="n">ms</span> <span class="mi">42</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.0</span><span class="o">%</span>
<span class="n">PythonFunctionCalls</span><span class="p">:</span> <span class="mi">39</span><span class="n">ms</span> <span class="mi">38</span><span class="n">ms</span> <span class="o">+</span><span class="mf">3.5</span><span class="o">%</span> <span class="mi">39</span><span class="n">ms</span> <span class="mi">38</span><span class="n">ms</span> <span class="o">+</span><span class="mf">2.8</span><span class="o">%</span>
<span class="n">PythonMethodCalls</span><span class="p">:</span> <span class="mi">51</span><span class="n">ms</span> <span class="mi">49</span><span class="n">ms</span> <span class="o">+</span><span class="mf">3.0</span><span class="o">%</span> <span class="mi">51</span><span class="n">ms</span> <span class="mi">50</span><span class="n">ms</span> <span class="o">+</span><span class="mf">2.8</span><span class="o">%</span>
<span class="n">Recursion</span><span class="p">:</span> <span class="mi">67</span><span class="n">ms</span> <span class="mi">68</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.4</span><span class="o">%</span> <span class="mi">67</span><span class="n">ms</span> <span class="mi">68</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.4</span><span class="o">%</span>
<span class="n">SecondImport</span><span class="p">:</span> <span class="mi">41</span><span class="n">ms</span> <span class="mi">36</span><span class="n">ms</span> <span class="o">+</span><span class="mf">12.5</span><span class="o">%</span> <span class="mi">41</span><span class="n">ms</span> <span class="mi">36</span><span class="n">ms</span> <span class="o">+</span><span class="mf">12.6</span><span class="o">%</span>
<span class="n">SecondPackageImport</span><span class="p">:</span> <span class="mi">45</span><span class="n">ms</span> <span class="mi">40</span><span class="n">ms</span> <span class="o">+</span><span class="mf">13.1</span><span class="o">%</span> <span class="mi">45</span><span class="n">ms</span> <span class="mi">40</span><span class="n">ms</span> <span class="o">+</span><span class="mf">13.2</span><span class="o">%</span>
<span class="n">SecondSubmoduleImport</span><span class="p">:</span> <span class="mi">92</span><span class="n">ms</span> <span class="mi">95</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.4</span><span class="o">%</span> <span class="mi">95</span><span class="n">ms</span> <span class="mi">98</span><span class="n">ms</span> <span class="o">-</span><span class="mf">3.6</span><span class="o">%</span>
<span class="n">SimpleComplexArithmetic</span><span class="p">:</span> <span class="mi">28</span><span class="n">ms</span> <span class="mi">28</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.1</span><span class="o">%</span> <span class="mi">28</span><span class="n">ms</span> <span class="mi">28</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.2</span><span class="o">%</span>
<span class="n">SimpleDictManipulation</span><span class="p">:</span> <span class="mi">57</span><span class="n">ms</span> <span class="mi">57</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.0</span><span class="o">%</span> <span class="mi">57</span><span class="n">ms</span> <span class="mi">58</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.0</span><span class="o">%</span>
<span class="n">SimpleFloatArithmetic</span><span class="p">:</span> <span class="mi">29</span><span class="n">ms</span> <span class="mi">28</span><span class="n">ms</span> <span class="o">+</span><span class="mf">4.7</span><span class="o">%</span> <span class="mi">29</span><span class="n">ms</span> <span class="mi">28</span><span class="n">ms</span> <span class="o">+</span><span class="mf">4.9</span><span class="o">%</span>
<span class="n">SimpleIntFloatArithmetic</span><span class="p">:</span> <span class="mi">37</span><span class="n">ms</span> <span class="mi">41</span><span class="n">ms</span> <span class="o">-</span><span class="mf">8.5</span><span class="o">%</span> <span class="mi">37</span><span class="n">ms</span> <span class="mi">41</span><span class="n">ms</span> <span class="o">-</span><span class="mf">8.7</span><span class="o">%</span>
<span class="n">SimpleIntegerArithmetic</span><span class="p">:</span> <span class="mi">37</span><span class="n">ms</span> <span class="mi">41</span><span class="n">ms</span> <span class="o">-</span><span class="mf">9.4</span><span class="o">%</span> <span class="mi">37</span><span class="n">ms</span> <span class="mi">42</span><span class="n">ms</span> <span class="o">-</span><span class="mf">10.2</span><span class="o">%</span>
<span class="n">SimpleListComprehensions</span><span class="p">:</span> <span class="mi">33</span><span class="n">ms</span> <span class="mi">33</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.9</span><span class="o">%</span> <span class="mi">33</span><span class="n">ms</span> <span class="mi">34</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.9</span><span class="o">%</span>
<span class="n">SimpleListManipulation</span><span class="p">:</span> <span class="mi">28</span><span class="n">ms</span> <span class="mi">30</span><span class="n">ms</span> <span class="o">-</span><span class="mf">4.3</span><span class="o">%</span> <span class="mi">29</span><span class="n">ms</span> <span class="mi">30</span><span class="n">ms</span> <span class="o">-</span><span class="mf">4.1</span><span class="o">%</span>
<span class="n">SimpleLongArithmetic</span><span class="p">:</span> <span class="mi">26</span><span class="n">ms</span> <span class="mi">26</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.5</span><span class="o">%</span> <span class="mi">26</span><span class="n">ms</span> <span class="mi">26</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.5</span><span class="o">%</span>
<span class="n">SmallLists</span><span class="p">:</span> <span class="mi">40</span><span class="n">ms</span> <span class="mi">40</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.1</span><span class="o">%</span> <span class="mi">40</span><span class="n">ms</span> <span class="mi">40</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.1</span><span class="o">%</span>
<span class="n">SmallTuples</span><span class="p">:</span> <span class="mi">46</span><span class="n">ms</span> <span class="mi">47</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.4</span><span class="o">%</span> <span class="mi">46</span><span class="n">ms</span> <span class="mi">48</span><span class="n">ms</span> <span class="o">-</span><span class="mf">3.0</span><span class="o">%</span>
<span class="n">SpecialClassAttribute</span><span class="p">:</span> <span class="mi">126</span><span class="n">ms</span> <span class="mi">120</span><span class="n">ms</span> <span class="o">+</span><span class="mf">4.7</span><span class="o">%</span> <span class="mi">126</span><span class="n">ms</span> <span class="mi">121</span><span class="n">ms</span> <span class="o">+</span><span class="mf">4.4</span><span class="o">%</span>
<span class="n">SpecialInstanceAttribute</span><span class="p">:</span> <span class="mi">42</span><span class="n">ms</span> <span class="mi">42</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.6</span><span class="o">%</span> <span class="mi">42</span><span class="n">ms</span> <span class="mi">42</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.8</span><span class="o">%</span>
<span class="n">StringMappings</span><span class="p">:</span> <span class="mi">94</span><span class="n">ms</span> <span class="mi">91</span><span class="n">ms</span> <span class="o">+</span><span class="mf">3.9</span><span class="o">%</span> <span class="mi">94</span><span class="n">ms</span> <span class="mi">91</span><span class="n">ms</span> <span class="o">+</span><span class="mf">3.8</span><span class="o">%</span>
<span class="n">StringPredicates</span><span class="p">:</span> <span class="mi">48</span><span class="n">ms</span> <span class="mi">49</span><span class="n">ms</span> <span class="o">-</span><span class="mf">1.7</span><span class="o">%</span> <span class="mi">48</span><span class="n">ms</span> <span class="mi">49</span><span class="n">ms</span> <span class="o">-</span><span class="mf">2.1</span><span class="o">%</span>
<span class="n">StringSlicing</span><span class="p">:</span> <span class="mi">45</span><span class="n">ms</span> <span class="mi">45</span><span class="n">ms</span> <span class="o">+</span><span class="mf">1.4</span><span class="o">%</span> <span class="mi">46</span><span class="n">ms</span> <span class="mi">45</span><span class="n">ms</span> <span class="o">+</span><span class="mf">1.5</span><span class="o">%</span>
<span class="n">TryExcept</span><span class="p">:</span> <span class="mi">23</span><span class="n">ms</span> <span class="mi">22</span><span class="n">ms</span> <span class="o">+</span><span class="mf">4.9</span><span class="o">%</span> <span class="mi">23</span><span class="n">ms</span> <span class="mi">22</span><span class="n">ms</span> <span class="o">+</span><span class="mf">4.8</span><span class="o">%</span>
<span class="n">TryFinally</span><span class="p">:</span> <span class="mi">32</span><span class="n">ms</span> <span class="mi">32</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.1</span><span class="o">%</span> <span class="mi">32</span><span class="n">ms</span> <span class="mi">32</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.1</span><span class="o">%</span>
<span class="n">TryRaiseExcept</span><span class="p">:</span> <span class="mi">17</span><span class="n">ms</span> <span class="mi">17</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.9</span><span class="o">%</span> <span class="mi">17</span><span class="n">ms</span> <span class="mi">17</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.5</span><span class="o">%</span>
<span class="n">TupleSlicing</span><span class="p">:</span> <span class="mi">49</span><span class="n">ms</span> <span class="mi">48</span><span class="n">ms</span> <span class="o">+</span><span class="mf">1.1</span><span class="o">%</span> <span class="mi">49</span><span class="n">ms</span> <span class="mi">49</span><span class="n">ms</span> <span class="o">+</span><span class="mf">1.0</span><span class="o">%</span>
<span class="n">WithFinally</span><span class="p">:</span> <span class="mi">48</span><span class="n">ms</span> <span class="mi">47</span><span class="n">ms</span> <span class="o">+</span><span class="mf">2.3</span><span class="o">%</span> <span class="mi">48</span><span class="n">ms</span> <span class="mi">47</span><span class="n">ms</span> <span class="o">+</span><span class="mf">2.4</span><span class="o">%</span>
<span class="n">WithRaiseExcept</span><span class="p">:</span> <span class="mi">45</span><span class="n">ms</span> <span class="mi">44</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.8</span><span class="o">%</span> <span class="mi">45</span><span class="n">ms</span> <span class="mi">45</span><span class="n">ms</span> <span class="o">+</span><span class="mf">0.5</span><span class="o">%</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">Totals</span><span class="p">:</span> <span class="mi">2284</span><span class="n">ms</span> <span class="mi">2287</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.1</span><span class="o">%</span> <span class="mi">2306</span><span class="n">ms</span> <span class="mi">2308</span><span class="n">ms</span> <span class="o">-</span><span class="mf">0.1</span><span class="o">%</span>
<span class="p">(</span><span class="n">this</span><span class="o">=</span><span class="n">pep447</span><span class="o">.</span><span class="n">pybench</span><span class="p">,</span> <span class="n">other</span><span class="o">=</span><span class="n">default</span><span class="o">.</span><span class="n">pybench</span><span class="p">)</span>
</pre></div>
</div>
<p>A run of the benchmark suite (with option “-b 2n3”) also seems to indicate that
the performance impact is minimal:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Report</span> <span class="n">on</span> <span class="n">Linux</span> <span class="n">fangorn</span><span class="o">.</span><span class="n">local</span> <span class="mf">2.6.32</span><span class="o">-</span><span class="mf">358.114.1</span><span class="o">.</span><span class="n">openstack</span><span class="o">.</span><span class="n">el6</span><span class="o">.</span><span class="n">x86_64</span> <span class="c1">#1 SMP Wed Jul 3 02:11:25 EDT 2013 x86_64 x86_64</span>
<span class="n">Total</span> <span class="n">CPU</span> <span class="n">cores</span><span class="p">:</span> <span class="mi">8</span>
<span class="c1">### call_method_slots ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.304120</span> <span class="o">-&gt;</span> <span class="mf">0.282791</span><span class="p">:</span> <span class="mf">1.08</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.304394</span> <span class="o">-&gt;</span> <span class="mf">0.282906</span><span class="p">:</span> <span class="mf">1.08</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=</span><span class="mf">2329.92</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00016</span> <span class="o">-&gt;</span> <span class="mf">0.00004</span><span class="p">:</span> <span class="mf">4.1814</span><span class="n">x</span> <span class="n">smaller</span>
<span class="c1">### call_simple ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.249268</span> <span class="o">-&gt;</span> <span class="mf">0.221175</span><span class="p">:</span> <span class="mf">1.13</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.249789</span> <span class="o">-&gt;</span> <span class="mf">0.221387</span><span class="p">:</span> <span class="mf">1.13</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=</span><span class="mf">2770.11</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00012</span> <span class="o">-&gt;</span> <span class="mf">0.00013</span><span class="p">:</span> <span class="mf">1.1101</span><span class="n">x</span> <span class="n">larger</span>
<span class="c1">### django_v2 ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.632590</span> <span class="o">-&gt;</span> <span class="mf">0.601519</span><span class="p">:</span> <span class="mf">1.05</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.635085</span> <span class="o">-&gt;</span> <span class="mf">0.602653</span><span class="p">:</span> <span class="mf">1.05</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=</span><span class="mf">321.32</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00087</span> <span class="o">-&gt;</span> <span class="mf">0.00051</span><span class="p">:</span> <span class="mf">1.6933</span><span class="n">x</span> <span class="n">smaller</span>
<span class="c1">### fannkuch ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">1.033181</span> <span class="o">-&gt;</span> <span class="mf">0.999779</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">1.036457</span> <span class="o">-&gt;</span> <span class="mf">1.001840</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=</span><span class="mf">260.31</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00113</span> <span class="o">-&gt;</span> <span class="mf">0.00070</span><span class="p">:</span> <span class="mf">1.6112</span><span class="n">x</span> <span class="n">smaller</span>
<span class="c1">### go ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.526714</span> <span class="o">-&gt;</span> <span class="mf">0.544428</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.529649</span> <span class="o">-&gt;</span> <span class="mf">0.547626</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=-</span><span class="mf">93.32</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00136</span> <span class="o">-&gt;</span> <span class="mf">0.00136</span><span class="p">:</span> <span class="mf">1.0028</span><span class="n">x</span> <span class="n">smaller</span>
<span class="c1">### iterative_count ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.109748</span> <span class="o">-&gt;</span> <span class="mf">0.116513</span><span class="p">:</span> <span class="mf">1.06</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.109816</span> <span class="o">-&gt;</span> <span class="mf">0.117202</span><span class="p">:</span> <span class="mf">1.07</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=-</span><span class="mf">357.08</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00008</span> <span class="o">-&gt;</span> <span class="mf">0.00019</span><span class="p">:</span> <span class="mf">2.3664</span><span class="n">x</span> <span class="n">larger</span>
<span class="c1">### json_dump_v2 ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">2.554462</span> <span class="o">-&gt;</span> <span class="mf">2.609141</span><span class="p">:</span> <span class="mf">1.02</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">2.564472</span> <span class="o">-&gt;</span> <span class="mf">2.620013</span><span class="p">:</span> <span class="mf">1.02</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=-</span><span class="mf">76.93</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00538</span> <span class="o">-&gt;</span> <span class="mf">0.00481</span><span class="p">:</span> <span class="mf">1.1194</span><span class="n">x</span> <span class="n">smaller</span>
<span class="c1">### meteor_contest ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.196336</span> <span class="o">-&gt;</span> <span class="mf">0.191925</span><span class="p">:</span> <span class="mf">1.02</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.196878</span> <span class="o">-&gt;</span> <span class="mf">0.192698</span><span class="p">:</span> <span class="mf">1.02</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=</span><span class="mf">61.86</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00053</span> <span class="o">-&gt;</span> <span class="mf">0.00041</span><span class="p">:</span> <span class="mf">1.2925</span><span class="n">x</span> <span class="n">smaller</span>
<span class="c1">### nbody ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.228039</span> <span class="o">-&gt;</span> <span class="mf">0.235551</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.228857</span> <span class="o">-&gt;</span> <span class="mf">0.236052</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=-</span><span class="mf">54.15</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00130</span> <span class="o">-&gt;</span> <span class="mf">0.00029</span><span class="p">:</span> <span class="mf">4.4810</span><span class="n">x</span> <span class="n">smaller</span>
<span class="c1">### pathlib ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.108501</span> <span class="o">-&gt;</span> <span class="mf">0.105339</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.109084</span> <span class="o">-&gt;</span> <span class="mf">0.105619</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=</span><span class="mf">311.08</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00022</span> <span class="o">-&gt;</span> <span class="mf">0.00011</span><span class="p">:</span> <span class="mf">1.9314</span><span class="n">x</span> <span class="n">smaller</span>
<span class="c1">### regex_effbot ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.057905</span> <span class="o">-&gt;</span> <span class="mf">0.056447</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.058055</span> <span class="o">-&gt;</span> <span class="mf">0.056760</span><span class="p">:</span> <span class="mf">1.02</span><span class="n">x</span> <span class="n">faster</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=</span><span class="mf">79.22</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00006</span> <span class="o">-&gt;</span> <span class="mf">0.00015</span><span class="p">:</span> <span class="mf">2.7741</span><span class="n">x</span> <span class="n">larger</span>
<span class="c1">### silent_logging ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.070810</span> <span class="o">-&gt;</span> <span class="mf">0.072436</span><span class="p">:</span> <span class="mf">1.02</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.070899</span> <span class="o">-&gt;</span> <span class="mf">0.072609</span><span class="p">:</span> <span class="mf">1.02</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=-</span><span class="mf">191.59</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00004</span> <span class="o">-&gt;</span> <span class="mf">0.00008</span><span class="p">:</span> <span class="mf">2.2640</span><span class="n">x</span> <span class="n">larger</span>
<span class="c1">### spectral_norm ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.290255</span> <span class="o">-&gt;</span> <span class="mf">0.299286</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.290335</span> <span class="o">-&gt;</span> <span class="mf">0.299541</span><span class="p">:</span> <span class="mf">1.03</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=-</span><span class="mf">572.10</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00005</span> <span class="o">-&gt;</span> <span class="mf">0.00015</span><span class="p">:</span> <span class="mf">2.8547</span><span class="n">x</span> <span class="n">larger</span>
<span class="c1">### threaded_count ###</span>
<span class="n">Min</span><span class="p">:</span> <span class="mf">0.107215</span> <span class="o">-&gt;</span> <span class="mf">0.115206</span><span class="p">:</span> <span class="mf">1.07</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Avg</span><span class="p">:</span> <span class="mf">0.107488</span> <span class="o">-&gt;</span> <span class="mf">0.115996</span><span class="p">:</span> <span class="mf">1.08</span><span class="n">x</span> <span class="n">slower</span>
<span class="n">Significant</span> <span class="p">(</span><span class="n">t</span><span class="o">=-</span><span class="mf">109.39</span><span class="p">)</span>
<span class="n">Stddev</span><span class="p">:</span> <span class="mf">0.00016</span> <span class="o">-&gt;</span> <span class="mf">0.00076</span><span class="p">:</span> <span class="mf">4.8665</span><span class="n">x</span> <span class="n">larger</span>
<span class="n">The</span> <span class="n">following</span> <span class="ow">not</span> <span class="n">significant</span> <span class="n">results</span> <span class="n">are</span> <span class="n">hidden</span><span class="p">,</span> <span class="n">use</span> <span class="o">-</span><span class="n">v</span> <span class="n">to</span> <span class="n">show</span> <span class="n">them</span><span class="p">:</span>
<span class="n">call_method</span><span class="p">,</span> <span class="n">call_method_unknown</span><span class="p">,</span> <span class="n">chaos</span><span class="p">,</span> <span class="n">fastpickle</span><span class="p">,</span> <span class="n">fastunpickle</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="n">formatted_logging</span><span class="p">,</span> <span class="n">hexiom2</span><span class="p">,</span> <span class="n">json_load</span><span class="p">,</span> <span class="n">normal_startup</span><span class="p">,</span> <span class="n">nqueens</span><span class="p">,</span> <span class="n">pidigits</span><span class="p">,</span> <span class="n">raytrace</span><span class="p">,</span> <span class="n">regex_compile</span><span class="p">,</span> <span class="n">regex_v8</span><span class="p">,</span> <span class="n">richards</span><span class="p">,</span> <span class="n">simple_logging</span><span class="p">,</span> <span class="n">startup_nosite</span><span class="p">,</span> <span class="n">telco</span><span class="p">,</span> <span class="n">unpack_sequence</span><span class="o">.</span>
</pre></div>
</div>
</section>
</section>
<section id="alternative-proposals">
<h2><a class="toc-backref" href="#alternative-proposals" role="doc-backlink">Alternative proposals</a></h2>
<section id="getattribute-super">
<h3><a class="toc-backref" href="#getattribute-super" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">__getattribute_super__</span></code></a></h3>
<p>An earlier version of this PEP used the following static method on classes:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">__getattribute_super__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="nb">object</span><span class="p">,</span> <span class="n">owner</span><span class="p">):</span> <span class="k">pass</span>
</pre></div>
</div>
<p>This method performed name lookup as well as invoking descriptors and was
necessarily limited to working only with <code class="docutils literal notranslate"><span class="pre">super.__getattribute__</span></code>.</p>
</section>
<section id="reuse-tp-getattro">
<h3><a class="toc-backref" href="#reuse-tp-getattro" role="doc-backlink">Reuse <code class="docutils literal notranslate"><span class="pre">tp_getattro</span></code></a></h3>
<p>It would be nice to avoid adding a new slot, thus keeping the API simpler and
easier to understand. A comment on <a class="reference external" href="http://bugs.python.org/issue18181">Issue 18181</a> asked about reusing the
<code class="docutils literal notranslate"><span class="pre">tp_getattro</span></code> slot, that is super could call the <code class="docutils literal notranslate"><span class="pre">tp_getattro</span></code> slot of all
methods along the MRO.</p>
<p>That wont work because <code class="docutils literal notranslate"><span class="pre">tp_getattro</span></code> will look in the instance
<code class="docutils literal notranslate"><span class="pre">__dict__</span></code> before it tries to resolve attributes using classes in the MRO.
This would mean that using <code class="docutils literal notranslate"><span class="pre">tp_getattro</span></code> instead of peeking the class
dictionaries changes the semantics of the <a class="reference external" href="http://docs.python.org/3/library/functions.html#super">super class</a>.</p>
</section>
<section id="alternative-placement-of-the-new-method">
<h3><a class="toc-backref" href="#alternative-placement-of-the-new-method" role="doc-backlink">Alternative placement of the new method</a></h3>
<p>This PEP proposes to add <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code> as a method on the metaclass.
An alternative would be to add it as a class method on the class itself
(similar to how <code class="docutils literal notranslate"><span class="pre">__new__</span></code> is a <a class="reference external" href="http://docs.python.org/3/library/functions.html#staticmethod">staticmethod</a> of the class and not a method
of the metaclass).</p>
<p>The advantage of using a method on the metaclass is that will give an error
when two classes on the MRO have different metaclasses that may have different
behaviors for <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code>. With a normal classmethod that problem
would pass undetected while it might cause subtle errors when running the code.</p>
</section>
</section>
<section id="history">
<h2><a class="toc-backref" href="#history" role="doc-backlink">History</a></h2>
<ul>
<li>23-Jul-2015: Added type flag <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_GETDESCRIPTOR</span></code> after talking
with Guido.<p>The new flag is primarily useful to avoid crashing when loading an extension
for an older version of CPython and could have positive speed implications
as well.</p>
</li>
<li>Jul-2014: renamed slot to <code class="docutils literal notranslate"><span class="pre">__getdescriptor__</span></code>, the old name didnt
match the naming style of other slots and was less descriptive.</li>
</ul>
</section>
<section id="discussion-threads">
<h2><a class="toc-backref" href="#discussion-threads" role="doc-backlink">Discussion threads</a></h2>
<ul class="simple">
<li>The initial version of the PEP was send with
Message-ID <a class="reference external" href="mailto:75030FAC-6918-4E94-95DA-67A88D53E6F5&#37;&#52;&#48;mac&#46;com">mailto:75030FAC-6918-4E94-95DA-67A88D53E6F5<span>&#64;</span>mac<span>&#46;</span>com</a></li>
<li>Further discussion starting at a message with
Message-ID <a class="reference external" href="mailto:5BB87CC4-F31B-4213-AAAC-0C0CE738460C&#37;&#52;&#48;mac&#46;com">mailto:5BB87CC4-F31B-4213-AAAC-0C0CE738460C<span>&#64;</span>mac<span>&#46;</span>com</a></li>
<li>And more discussion starting at message with
Message-ID <a class="reference external" href="mailto:00AA7433-C853-4101-9718-060468EBAC54&#37;&#52;&#48;mac&#46;com">mailto:00AA7433-C853-4101-9718-060468EBAC54<span>&#64;</span>mac<span>&#46;</span>com</a></li>
</ul>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<ul class="simple">
<li><a class="reference external" href="http://bugs.python.org/issue18181">Issue 18181</a> contains an out of date prototype implementation</li>
</ul>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0447.rst">https://github.com/python/peps/blob/main/peps/pep-0447.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0447.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="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#pep-status">PEP Status</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#background">Background</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-superclass-attribute-lookup-hook">The superclass attribute lookup hook</a><ul>
<li><a class="reference internal" href="#aside-attribute-resolution-algorithm-in-python">Aside: Attribute resolution algorithm in Python</a></li>
<li><a class="reference internal" href="#in-python-code">In Python code</a><ul>
<li><a class="reference internal" href="#example-usage">Example usage</a></li>
</ul>
</li>
<li><a class="reference internal" href="#in-c-code">In C code</a></li>
<li><a class="reference internal" href="#use-of-this-hook-by-the-interpreter">Use of this hook by the interpreter</a></li>
<li><a class="reference internal" href="#other-changes-to-the-implementation">Other changes to the implementation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#impact-of-this-pep-on-introspection">Impact of this PEP on introspection</a></li>
<li><a class="reference internal" href="#performance-impact">Performance impact</a><ul>
<li><a class="reference internal" href="#micro-benchmarks">Micro benchmarks</a></li>
<li><a class="reference internal" href="#pybench">Pybench</a></li>
</ul>
</li>
<li><a class="reference internal" href="#alternative-proposals">Alternative proposals</a><ul>
<li><a class="reference internal" href="#getattribute-super"><code class="docutils literal notranslate"><span class="pre">__getattribute_super__</span></code></a></li>
<li><a class="reference internal" href="#reuse-tp-getattro">Reuse <code class="docutils literal notranslate"><span class="pre">tp_getattro</span></code></a></li>
<li><a class="reference internal" href="#alternative-placement-of-the-new-method">Alternative placement of the new method</a></li>
</ul>
</li>
<li><a class="reference internal" href="#history">History</a></li>
<li><a class="reference internal" href="#discussion-threads">Discussion threads</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0447.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>