mirror of https://github.com/python/peps
803 lines
99 KiB
HTML
803 lines
99 KiB
HTML
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="color-scheme" content="light dark">
|
||
<title>PEP 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> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </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 <ronaldoussoren at mac.com></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 doesn’t
|
||
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 object’s 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 CPython’s 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">'__class__'</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">"fortytwo"</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">"fortytwo"</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"><<</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> won’t cause problems
|
||
because that still only uses the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> and won’t 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 I’ve ported the patch to the current trunk. I don’t 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,
|
||
I’ve 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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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 won’t 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 didn’t
|
||
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%40mac.com">mailto:75030FAC-6918-4E94-95DA-67A88D53E6F5<span>@</span>mac<span>.</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%40mac.com">mailto:5BB87CC4-F31B-4213-AAAC-0C0CE738460C<span>@</span>mac<span>.</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%40mac.com">mailto:00AA7433-C853-4101-9718-060468EBAC54<span>@</span>mac<span>.</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> |