mirror of https://github.com/python/peps
862 lines
82 KiB
HTML
862 lines
82 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 580 – The C call protocol | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0580/">
|
||
<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 580 – The C call protocol | peps.python.org'>
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0580/">
|
||
<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 580</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 580 – The C call protocol</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Jeroen Demeyer <J.Demeyer at UGent.be></dd>
|
||
<dt class="field-even">BDFL-Delegate<span class="colon">:</span></dt>
|
||
<dd class="field-even">Petr Viktorin</dd>
|
||
<dt class="field-odd">Status<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><abbr title="Formally declined and will not be accepted">Rejected</abbr></dd>
|
||
<dt class="field-even">Type<span class="colon">:</span></dt>
|
||
<dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
|
||
<dt class="field-odd">Created<span class="colon">:</span></dt>
|
||
<dd class="field-odd">14-Jun-2018</dd>
|
||
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-even">3.8</dd>
|
||
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-odd">20-Jun-2018, 22-Jun-2018, 16-Jul-2018</dd>
|
||
</dl>
|
||
<hr class="docutils" />
|
||
<section id="contents">
|
||
<details><summary>Table of Contents</summary><ul class="simple">
|
||
<li><a class="reference internal" href="#rejection-notice">Rejection Notice</a></li>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a></li>
|
||
<li><a class="reference internal" href="#overview">Overview</a></li>
|
||
<li><a class="reference internal" href="#new-data-structures">New data structures</a><ul>
|
||
<li><a class="reference internal" href="#parent">Parent</a></li>
|
||
<li><a class="reference internal" href="#using-tp-print">Using tp_print</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#the-c-call-protocol">The C call protocol</a><ul>
|
||
<li><a class="reference internal" href="#checking-objclass">Checking __objclass__</a></li>
|
||
<li><a class="reference internal" href="#self-slicing">Self slicing</a></li>
|
||
<li><a class="reference internal" href="#descriptor-behavior">Descriptor behavior</a></li>
|
||
<li><a class="reference internal" href="#the-name-attribute">The __name__ attribute</a></li>
|
||
<li><a class="reference internal" href="#generic-api-functions">Generic API functions</a></li>
|
||
<li><a class="reference internal" href="#profiling">Profiling</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#changes-to-built-in-functions-and-methods">Changes to built-in functions and methods</a><ul>
|
||
<li><a class="reference internal" href="#c-api-functions">C API functions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#inheritance">Inheritance</a></li>
|
||
<li><a class="reference internal" href="#performance">Performance</a></li>
|
||
<li><a class="reference internal" href="#stable-abi">Stable ABI</a></li>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards compatibility</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
|
||
<li><a class="reference internal" href="#why-is-this-better-than-pep-575">Why is this better than PEP 575?</a></li>
|
||
<li><a class="reference internal" href="#why-store-the-function-pointer-in-the-instance">Why store the function pointer in the instance?</a></li>
|
||
<li><a class="reference internal" href="#why-ccall-objclass">Why CCALL_OBJCLASS?</a></li>
|
||
<li><a class="reference internal" href="#why-ccall-selfarg">Why CCALL_SELFARG?</a></li>
|
||
<li><a class="reference internal" href="#why-ccall-defarg">Why CCALL_DEFARG?</a></li>
|
||
<li><a class="reference internal" href="#replacing-tp-print">Replacing tp_print</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#alternative-suggestions">Alternative suggestions</a></li>
|
||
<li><a class="reference internal" href="#discussion">Discussion</a></li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference implementation</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="rejection-notice">
|
||
<h2><a class="toc-backref" href="#rejection-notice" role="doc-backlink">Rejection Notice</a></h2>
|
||
<p>This PEP is rejected in favor of <a class="pep reference internal" href="../pep-0590/" title="PEP 590 – Vectorcall: a fast calling protocol for CPython">PEP 590</a>, which proposes a simpler public
|
||
C API for callable objects.</p>
|
||
</section>
|
||
<section id="abstract">
|
||
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
||
<p>A new “C call” protocol is proposed.
|
||
It is meant for classes representing functions or methods
|
||
which need to implement fast calling.
|
||
The goal is to generalize all existing optimizations for built-in functions
|
||
to arbitrary extension types.</p>
|
||
<p>In the reference implementation,
|
||
this new protocol is used for the existing classes
|
||
<code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> and <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code>.
|
||
However, in the future, more classes may implement it.</p>
|
||
<p><strong>NOTE</strong>: This PEP deals only with the Python/C API,
|
||
it does not affect the Python language or standard library.</p>
|
||
</section>
|
||
<section id="motivation">
|
||
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
||
<p>The standard function/method classes <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code> allow very efficiently calling C code.
|
||
However, they are not subclassable, making them unsuitable for many applications:
|
||
for example, they offer limited introspection support
|
||
(signatures only using <code class="docutils literal notranslate"><span class="pre">__text_signature__</span></code>, no arbitrary <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code>,
|
||
no <code class="docutils literal notranslate"><span class="pre">inspect.getfile()</span></code>).
|
||
It’s also not possible to store additional data to implement something like
|
||
<code class="docutils literal notranslate"><span class="pre">functools.partial</span></code> or <code class="docutils literal notranslate"><span class="pre">functools.lru_cache</span></code>.
|
||
So, there are many reasons why users would want to implement custom
|
||
function/method classes (in a duck-typing sense) in C.
|
||
Unfortunately, such custom classes are necessarily slower than
|
||
the standard CPython function classes:
|
||
the bytecode interpreter has various optimizations
|
||
which are specific to instances of
|
||
<code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code>, <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code>, <code class="docutils literal notranslate"><span class="pre">method</span></code> and <code class="docutils literal notranslate"><span class="pre">function</span></code>.</p>
|
||
<p>This PEP also allows to simplify existing code:
|
||
checks for <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> and <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code>
|
||
could be replaced by simply checking for and using the C call protocol.
|
||
Future PEPs may implement the C call protocol for more classes,
|
||
enabling even further simplifications.</p>
|
||
<p>We also design the C call protocol such that it can easily
|
||
be extended with new features in the future.</p>
|
||
<p>For more background and motivation, see <a class="pep reference internal" href="../pep-0579/" title="PEP 579 – Refactoring C functions and methods">PEP 579</a>.</p>
|
||
</section>
|
||
<section id="overview">
|
||
<h2><a class="toc-backref" href="#overview" role="doc-backlink">Overview</a></h2>
|
||
<p>Currently, CPython has multiple optimizations for fast calling
|
||
for a few specific function classes.
|
||
A good example is the implementation of the opcode <code class="docutils literal notranslate"><span class="pre">CALL_FUNCTION</span></code>,
|
||
which has the following structure
|
||
(<a class="reference external" href="https://github.com/python/cpython/blob/7a2368063f25746d4008a74aca0dc0b82f86ff7b/Python/ceval.c#L4592">see the actual code</a>):</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">PyCFunction_Check</span><span class="p">(</span><span class="n">func</span><span class="p">))</span> <span class="p">{</span>
|
||
<span class="k">return</span> <span class="n">_PyCFunction_FastCallKeywords</span><span class="p">(</span><span class="n">func</span><span class="p">,</span> <span class="n">stack</span><span class="p">,</span> <span class="n">nargs</span><span class="p">,</span> <span class="n">kwnames</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">Py_TYPE</span><span class="p">(</span><span class="n">func</span><span class="p">)</span> <span class="o">==</span> <span class="o">&</span><span class="n">PyMethodDescr_Type</span><span class="p">)</span> <span class="p">{</span>
|
||
<span class="k">return</span> <span class="n">_PyMethodDescr_FastCallKeywords</span><span class="p">(</span><span class="n">func</span><span class="p">,</span> <span class="n">stack</span><span class="p">,</span> <span class="n">nargs</span><span class="p">,</span> <span class="n">kwnames</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
<span class="k">else</span> <span class="p">{</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">PyMethod_Check</span><span class="p">(</span><span class="n">func</span><span class="p">)</span> <span class="o">&&</span> <span class="n">PyMethod_GET_SELF</span><span class="p">(</span><span class="n">func</span><span class="p">)</span> <span class="o">!=</span> <span class="n">NULL</span><span class="p">)</span> <span class="p">{</span>
|
||
<span class="o">/*</span> <span class="o">...</span> <span class="o">*/</span>
|
||
<span class="p">}</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">PyFunction_Check</span><span class="p">(</span><span class="n">func</span><span class="p">))</span> <span class="p">{</span>
|
||
<span class="k">return</span> <span class="n">_PyFunction_FastCallKeywords</span><span class="p">(</span><span class="n">func</span><span class="p">,</span> <span class="n">stack</span><span class="p">,</span> <span class="n">nargs</span><span class="p">,</span> <span class="n">kwnames</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
<span class="k">else</span> <span class="p">{</span>
|
||
<span class="k">return</span> <span class="n">_PyObject_FastCallKeywords</span><span class="p">(</span><span class="n">func</span><span class="p">,</span> <span class="n">stack</span><span class="p">,</span> <span class="n">nargs</span><span class="p">,</span> <span class="n">kwnames</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Calling instances of these special-cased classes
|
||
using the <code class="docutils literal notranslate"><span class="pre">tp_call</span></code> slot is slower than using the optimizations.
|
||
The basic idea of this PEP is to enable such optimizations
|
||
for user C code, both as caller and as callee.</p>
|
||
<p>The existing class <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> and a few others
|
||
use a <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code> structure for describing the underlying C function and its signature.
|
||
The first concrete change is that this is replaced by a new structure <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code>.
|
||
This stores some of the same information as a <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code>,
|
||
but with one important addition:
|
||
the “parent” of the function (the class or module where it is defined).
|
||
Note that <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code> arrays are still used to construct
|
||
functions/methods but no longer for calling them.</p>
|
||
<p>Second, we want that every class can use such a <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> for optimizing calls,
|
||
so the <code class="docutils literal notranslate"><span class="pre">PyTypeObject</span></code> structure gains a <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span></code> field
|
||
giving an offset to a <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span> <span class="pre">*</span></code> in the object structure
|
||
and a flag <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_CCALL</span></code> indicating that <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span></code> is valid.</p>
|
||
<p>Third, since we want to deal efficiently with unbound and bound methods too
|
||
(as opposed to only plain functions), we need to handle <code class="docutils literal notranslate"><span class="pre">__self__</span></code> in the protocol:
|
||
after the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span> <span class="pre">*</span></code> in the object structure,
|
||
there is a <code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*self</span></code> field.
|
||
These two fields together are referred to as a <code class="docutils literal notranslate"><span class="pre">PyCCallRoot</span></code> structure.</p>
|
||
<p>The new protocol for efficiently calling objects using these new structures
|
||
is called the “C call protocol”.</p>
|
||
<p><strong>NOTE</strong>: In this PEP, the phrases “unbound method” and “bound method”
|
||
refer to generic behavior, not to specific classes.
|
||
For example, an unbound method gets turned into a bound method
|
||
after applying <code class="docutils literal notranslate"><span class="pre">__get__</span></code>.</p>
|
||
</section>
|
||
<section id="new-data-structures">
|
||
<h2><a class="toc-backref" href="#new-data-structures" role="doc-backlink">New data structures</a></h2>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">PyTypeObject</span></code> structure gains a new field <code class="docutils literal notranslate"><span class="pre">Py_ssize_t</span> <span class="pre">tp_ccalloffset</span></code>
|
||
and a new flag <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_CCALL</span></code>.
|
||
If this flag is set, then <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span></code> is assumed to be a valid
|
||
offset inside the object structure (similar to <code class="docutils literal notranslate"><span class="pre">tp_dictoffset</span></code> and <code class="docutils literal notranslate"><span class="pre">tp_weaklistoffset</span></code>).
|
||
It must be a strictly positive integer.
|
||
At that offset, a <code class="docutils literal notranslate"><span class="pre">PyCCallRoot</span></code> structure appears:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">typedef</span> <span class="n">struct</span> <span class="p">{</span>
|
||
<span class="n">const</span> <span class="n">PyCCallDef</span> <span class="o">*</span><span class="n">cr_ccall</span><span class="p">;</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">cr_self</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__self__</span> <span class="n">argument</span> <span class="k">for</span> <span class="n">methods</span> <span class="o">*/</span>
|
||
<span class="p">}</span> <span class="n">PyCCallRoot</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structure contains everything needed to describe how
|
||
the function can be called:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">typedef</span> <span class="n">struct</span> <span class="p">{</span>
|
||
<span class="n">uint32_t</span> <span class="n">cc_flags</span><span class="p">;</span>
|
||
<span class="n">PyCFunc</span> <span class="n">cc_func</span><span class="p">;</span> <span class="o">/*</span> <span class="n">C</span> <span class="n">function</span> <span class="n">to</span> <span class="n">call</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">cc_parent</span><span class="p">;</span> <span class="o">/*</span> <span class="k">class</span> <span class="nc">or</span> <span class="n">module</span> <span class="o">*/</span>
|
||
<span class="p">}</span> <span class="n">PyCCallDef</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The reason for putting <code class="docutils literal notranslate"><span class="pre">__self__</span></code> outside of <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code>
|
||
is that <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> is not meant to be changed after creating the function.
|
||
A single <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> can be shared
|
||
by an unbound method and multiple bound methods.
|
||
This wouldn’t work if we would put <code class="docutils literal notranslate"><span class="pre">__self__</span></code> inside that structure.</p>
|
||
<p><strong>NOTE</strong>: unlike <code class="docutils literal notranslate"><span class="pre">tp_dictoffset</span></code> we do not allow negative numbers
|
||
for <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span></code> to mean counting from the end.
|
||
There does not seem to be a use case for it and it would only complicate
|
||
the implementation.</p>
|
||
<section id="parent">
|
||
<h3><a class="toc-backref" href="#parent" role="doc-backlink">Parent</a></h3>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> field (accessed for example by a <code class="docutils literal notranslate"><span class="pre">__parent__</span></code>
|
||
or <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code> descriptor from Python code) can be any Python
|
||
object, or NULL.
|
||
Custom classes are free to set <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> to whatever they want.
|
||
It is only used by the C call protocol if the
|
||
<code class="docutils literal notranslate"><span class="pre">CCALL_OBJCLASS</span></code> flag is set.</p>
|
||
<p>For methods of extension types, <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> points to the class
|
||
that defines the method (which may be a superclass of <code class="docutils literal notranslate"><span class="pre">type(self)</span></code>).
|
||
This is currently non-trivial to retrieve from a method’s code.
|
||
In the future, this can be used to access the module state via
|
||
the defining class. See the rationale of <a class="pep reference internal" href="../pep-0573/" title="PEP 573 – Module State Access from C Extension Methods">PEP 573</a> for details.</p>
|
||
<p>When the flag <code class="docutils literal notranslate"><span class="pre">CCALL_OBJCLASS</span></code> is set (as it will be for methods of
|
||
extension types), <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> is used for type checks like the following:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">list</span><span class="o">.</span><span class="n">append</span><span class="p">({},</span> <span class="s2">"x"</span><span class="p">)</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
|
||
<span class="gr">TypeError</span>: <span class="n">descriptor 'append' requires a 'list' object but received a 'dict'</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>For functions of modules, <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> is set to the module.
|
||
Currently, this is exactly the same as <code class="docutils literal notranslate"><span class="pre">__self__</span></code>.
|
||
However, using <code class="docutils literal notranslate"><span class="pre">__self__</span></code> for the module is a quirk of the current implementation:
|
||
in the future, we want to allow functions which use <code class="docutils literal notranslate"><span class="pre">__self__</span></code>
|
||
in the normal way, for implementing methods.
|
||
Such functions can still use <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> instead to refer to the module.</p>
|
||
<p>The parent would also typically be used to implement <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code>.
|
||
The new C API function <code class="docutils literal notranslate"><span class="pre">PyCCall_GenericGetQualname()</span></code> does exactly that.</p>
|
||
</section>
|
||
<section id="using-tp-print">
|
||
<h3><a class="toc-backref" href="#using-tp-print" role="doc-backlink">Using tp_print</a></h3>
|
||
<p>We propose to replace the existing unused field <code class="docutils literal notranslate"><span class="pre">tp_print</span></code>
|
||
by <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span></code>.
|
||
Since <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_CCALL</span></code> would <em>not</em> be added to
|
||
<code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_DEFAULT</span></code>, this ensures full backwards compatibility for
|
||
existing extension modules setting <code class="docutils literal notranslate"><span class="pre">tp_print</span></code>.
|
||
It also means that we can require that <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span></code> is a valid
|
||
offset when <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_CCALL</span></code> is specified:
|
||
we do not need to check <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span> <span class="pre">!=</span> <span class="pre">0</span></code>.
|
||
In future Python versions, we may decide that <code class="docutils literal notranslate"><span class="pre">tp_print</span></code>
|
||
becomes <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span></code> unconditionally,
|
||
drop the <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_CCALL</span></code> flag and instead check for
|
||
<code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span> <span class="pre">!=</span> <span class="pre">0</span></code>.</p>
|
||
<p><strong>NOTE</strong>: the exact layout of <code class="docutils literal notranslate"><span class="pre">PyTypeObject</span></code> is not part of the <a class="pep reference internal" href="../pep-0384/" title="PEP 384 – Defining a Stable ABI">stable ABI</a>).
|
||
Therefore, changing the <code class="docutils literal notranslate"><span class="pre">tp_print</span></code> field from a <code class="docutils literal notranslate"><span class="pre">printfunc</span></code> (a function pointer)
|
||
to a <code class="docutils literal notranslate"><span class="pre">Py_ssize_t</span></code> should not be a problem,
|
||
even if this changes the memory layout of the <code class="docutils literal notranslate"><span class="pre">PyTypeObject</span></code> structure.
|
||
Moreover, on all systems for which binaries are commonly built
|
||
(Windows, Linux, macOS),
|
||
the size of <code class="docutils literal notranslate"><span class="pre">printfunc</span></code> and <code class="docutils literal notranslate"><span class="pre">Py_ssize_t</span></code> are the same,
|
||
so the issue of binary compatibility will not come up anyway.</p>
|
||
</section>
|
||
</section>
|
||
<section id="the-c-call-protocol">
|
||
<h2><a class="toc-backref" href="#the-c-call-protocol" role="doc-backlink">The C call protocol</a></h2>
|
||
<p>We say that a class implements the C call protocol
|
||
if it has the <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_CCALL</span></code> flag set
|
||
(as explained above, it must then set <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span> <span class="pre">></span> <span class="pre">0</span></code>).
|
||
Such a class must implement <code class="docutils literal notranslate"><span class="pre">__call__</span></code> as described in this section
|
||
(in practice, this just means setting <code class="docutils literal notranslate"><span class="pre">tp_call</span></code> to <code class="docutils literal notranslate"><span class="pre">PyCCall_Call</span></code>).</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">cc_func</span></code> field is a C function pointer,
|
||
which plays the same role as the existing <code class="docutils literal notranslate"><span class="pre">ml_meth</span></code> field of <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code>.
|
||
Its precise signature depends on flags.
|
||
The subset of flags influencing the signature of <code class="docutils literal notranslate"><span class="pre">cc_func</span></code>
|
||
is given by the bitmask <code class="docutils literal notranslate"><span class="pre">CCALL_SIGNATURE</span></code>.
|
||
Below are the possible values for <code class="docutils literal notranslate"><span class="pre">cc_flags</span> <span class="pre">&</span> <span class="pre">CCALL_SIGNATURE</span></code>
|
||
together with the arguments that the C function takes.
|
||
The return value is always <code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*</span></code>.
|
||
The following are analogous to the existing <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code>
|
||
signature flags:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">CCALL_VARARGS</span></code>:
|
||
<code class="docutils literal notranslate"><span class="pre">cc_func(PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*args)</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">CCALL_VARARGS</span> <span class="pre">|</span> <span class="pre">CCALL_KEYWORDS</span></code>:
|
||
<code class="docutils literal notranslate"><span class="pre">cc_func(PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*args,</span> <span class="pre">PyObject</span> <span class="pre">*kwds)</span></code>
|
||
(<code class="docutils literal notranslate"><span class="pre">kwds</span></code> is either <code class="docutils literal notranslate"><span class="pre">NULL</span></code> or a dict; this dict must not be modified by the callee)</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">CCALL_FASTCALL</span></code>:
|
||
<code class="docutils literal notranslate"><span class="pre">cc_func(PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*const</span> <span class="pre">*args,</span> <span class="pre">Py_ssize_t</span> <span class="pre">nargs)</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">CCALL_FASTCALL</span> <span class="pre">|</span> <span class="pre">CCALL_KEYWORDS</span></code>:
|
||
<code class="docutils literal notranslate"><span class="pre">cc_func(PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*const</span> <span class="pre">*args,</span> <span class="pre">Py_ssize_t</span> <span class="pre">nargs,</span> <span class="pre">PyObject</span> <span class="pre">*kwnames)</span></code>
|
||
(<code class="docutils literal notranslate"><span class="pre">kwnames</span></code> is either <code class="docutils literal notranslate"><span class="pre">NULL</span></code> or a non-empty tuple of keyword names)</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">CCALL_NOARGS</span></code>:
|
||
<code class="docutils literal notranslate"><span class="pre">cc_func(PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*unused)</span></code> (second argument is always <code class="docutils literal notranslate"><span class="pre">NULL</span></code>)</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">CCALL_O</span></code>:
|
||
<code class="docutils literal notranslate"><span class="pre">cc_func(PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*arg)</span></code></li>
|
||
</ul>
|
||
<p>The flag <code class="docutils literal notranslate"><span class="pre">CCALL_DEFARG</span></code> may be combined with any of these.
|
||
If so, the C function takes an additional argument
|
||
as first argument before <code class="docutils literal notranslate"><span class="pre">self</span></code>,
|
||
namely a const pointer to the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structure used for this call.
|
||
For example, we have the following signature:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">CCALL_DEFARG</span> <span class="pre">|</span> <span class="pre">CCALL_VARARGS</span></code>:
|
||
<code class="docutils literal notranslate"><span class="pre">cc_func(const</span> <span class="pre">PyCCallDef</span> <span class="pre">*def,</span> <span class="pre">PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*args)</span></code></li>
|
||
</ul>
|
||
<p>One exception is <code class="docutils literal notranslate"><span class="pre">CCALL_DEFARG</span> <span class="pre">|</span> <span class="pre">CCALL_NOARGS</span></code>:
|
||
the <code class="docutils literal notranslate"><span class="pre">unused</span></code> argument is dropped, so the signature becomes</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">CCALL_DEFARG</span> <span class="pre">|</span> <span class="pre">CCALL_NOARGS</span></code>:
|
||
<code class="docutils literal notranslate"><span class="pre">cc_func(const</span> <span class="pre">PyCCallDef</span> <span class="pre">*def,</span> <span class="pre">PyObject</span> <span class="pre">*self)</span></code></li>
|
||
</ul>
|
||
<p><strong>NOTE</strong>: unlike the existing <code class="docutils literal notranslate"><span class="pre">METH_...</span></code> flags,
|
||
the <code class="docutils literal notranslate"><span class="pre">CCALL_...</span></code> constants do not necessarily represent single bits.
|
||
So checking <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">(cc_flags</span> <span class="pre">&</span> <span class="pre">CCALL_VARARGS)</span></code> is not a valid way
|
||
for checking the signature.
|
||
There are also no guarantees of binary compatibility for these flags
|
||
between Python versions.
|
||
This allows the implementation to choose the most efficient
|
||
numerical values of the flags.
|
||
In the reference implementation,
|
||
the legal values for <code class="docutils literal notranslate"><span class="pre">cc_flags</span> <span class="pre">&</span> <span class="pre">CCALL_SIGNATURE</span></code> form exactly the interval [0, …, 11].
|
||
This means that the compiler can easily
|
||
optimize a <code class="docutils literal notranslate"><span class="pre">switch</span></code> statement for those cases using a computed goto.</p>
|
||
<section id="checking-objclass">
|
||
<h3><a class="toc-backref" href="#checking-objclass" role="doc-backlink">Checking __objclass__</a></h3>
|
||
<p>If the <code class="docutils literal notranslate"><span class="pre">CCALL_OBJCLASS</span></code> flag is set and if <code class="docutils literal notranslate"><span class="pre">cr_self</span></code> is NULL
|
||
(this is the case for unbound methods of extension types),
|
||
then a type check is done:
|
||
the function must be called with at least one positional argument
|
||
and the first (typically called <code class="docutils literal notranslate"><span class="pre">self</span></code>) must be an instance of
|
||
<code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> (which must be a class).
|
||
If not, a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> is raised.</p>
|
||
</section>
|
||
<section id="self-slicing">
|
||
<h3><a class="toc-backref" href="#self-slicing" role="doc-backlink">Self slicing</a></h3>
|
||
<p>If <code class="docutils literal notranslate"><span class="pre">cr_self</span></code> is not NULL or if the flag <code class="docutils literal notranslate"><span class="pre">CCALL_SELFARG</span></code>
|
||
is not set in <code class="docutils literal notranslate"><span class="pre">cc_flags</span></code>, then the argument passed as <code class="docutils literal notranslate"><span class="pre">self</span></code>
|
||
is simply <code class="docutils literal notranslate"><span class="pre">cr_self</span></code>.</p>
|
||
<p>If <code class="docutils literal notranslate"><span class="pre">cr_self</span></code> is NULL and the flag <code class="docutils literal notranslate"><span class="pre">CCALL_SELFARG</span></code> is set,
|
||
then the first positional argument is removed from
|
||
<code class="docutils literal notranslate"><span class="pre">args</span></code> and instead passed as <code class="docutils literal notranslate"><span class="pre">self</span></code> argument to the C function.
|
||
Effectively, the first positional argument is treated as <code class="docutils literal notranslate"><span class="pre">__self__</span></code>.
|
||
If there are no positional arguments, <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> is raised.</p>
|
||
<p>This process is called “self slicing” and a function is said to have self
|
||
slicing if <code class="docutils literal notranslate"><span class="pre">cr_self</span></code> is NULL and <code class="docutils literal notranslate"><span class="pre">CCALL_SELFARG</span></code> is set.</p>
|
||
<p>Note that a <code class="docutils literal notranslate"><span class="pre">CCALL_NOARGS</span></code> function with self slicing effectively has
|
||
one argument, namely <code class="docutils literal notranslate"><span class="pre">self</span></code>.
|
||
Analogously, a <code class="docutils literal notranslate"><span class="pre">CCALL_O</span></code> function with self slicing has two arguments.</p>
|
||
</section>
|
||
<section id="descriptor-behavior">
|
||
<h3><a class="toc-backref" href="#descriptor-behavior" role="doc-backlink">Descriptor behavior</a></h3>
|
||
<p>Classes supporting the C call protocol
|
||
must implement the descriptor protocol in a specific way.</p>
|
||
<p>This is required for an efficient implementation of bound methods:
|
||
if other code can make assumptions on what <code class="docutils literal notranslate"><span class="pre">__get__</span></code> does,
|
||
it enables optimizations which would not be possible otherwise.
|
||
In particular, we want to allow sharing
|
||
the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structure between bound and unbound methods.
|
||
We also need a correct implementation of <code class="docutils literal notranslate"><span class="pre">_PyObject_GetMethod</span></code>
|
||
which is used by the <code class="docutils literal notranslate"><span class="pre">LOAD_METHOD</span></code>/<code class="docutils literal notranslate"><span class="pre">CALL_METHOD</span></code> optimization.</p>
|
||
<p>First of all, if <code class="docutils literal notranslate"><span class="pre">func</span></code> supports the C call protocol,
|
||
then <code class="docutils literal notranslate"><span class="pre">func.__set__</span></code> and <code class="docutils literal notranslate"><span class="pre">func.__delete__</span></code> must not be implemented.</p>
|
||
<p>Second, <code class="docutils literal notranslate"><span class="pre">func.__get__</span></code> must behave as follows:</p>
|
||
<ul class="simple">
|
||
<li>If <code class="docutils literal notranslate"><span class="pre">cr_self</span></code> is not NULL, then <code class="docutils literal notranslate"><span class="pre">__get__</span></code> must be a no-op
|
||
in the sense that <code class="docutils literal notranslate"><span class="pre">func.__get__(obj,</span> <span class="pre">cls)(*args,</span> <span class="pre">**kwds)</span></code>
|
||
behaves exactly the same as <code class="docutils literal notranslate"><span class="pre">func(*args,</span> <span class="pre">**kwds)</span></code>.
|
||
It is also allowed for <code class="docutils literal notranslate"><span class="pre">__get__</span></code> to be not implemented at all.</li>
|
||
<li>If <code class="docutils literal notranslate"><span class="pre">cr_self</span></code> is NULL, then <code class="docutils literal notranslate"><span class="pre">func.__get__(obj,</span> <span class="pre">cls)(*args,</span> <span class="pre">**kwds)</span></code>
|
||
(with <code class="docutils literal notranslate"><span class="pre">obj</span></code> not None)
|
||
must be equivalent to <code class="docutils literal notranslate"><span class="pre">func(obj,</span> <span class="pre">*args,</span> <span class="pre">**kwds)</span></code>.
|
||
In particular, <code class="docutils literal notranslate"><span class="pre">__get__</span></code> must be implemented in this case.
|
||
This is unrelated to <a class="reference internal" href="#self-slicing">self slicing</a>: <code class="docutils literal notranslate"><span class="pre">obj</span></code> may be passed
|
||
as <code class="docutils literal notranslate"><span class="pre">self</span></code> argument to the C function or it may be the first positional argument.</li>
|
||
<li>If <code class="docutils literal notranslate"><span class="pre">cr_self</span></code> is NULL, then <code class="docutils literal notranslate"><span class="pre">func.__get__(None,</span> <span class="pre">cls)(*args,</span> <span class="pre">**kwds)</span></code>
|
||
must be equivalent to <code class="docutils literal notranslate"><span class="pre">func(*args,</span> <span class="pre">**kwds)</span></code>.</li>
|
||
</ul>
|
||
<p>There are no restrictions on the object <code class="docutils literal notranslate"><span class="pre">func.__get__(obj,</span> <span class="pre">cls)</span></code>.
|
||
The latter is not required to implement the C call protocol for example.
|
||
We only specify what <code class="docutils literal notranslate"><span class="pre">func.__get__(obj,</span> <span class="pre">cls).__call__</span></code> does.</p>
|
||
<p>For classes that do not care about <code class="docutils literal notranslate"><span class="pre">__self__</span></code> and <code class="docutils literal notranslate"><span class="pre">__get__</span></code> at all,
|
||
the easiest solution is to assign <code class="docutils literal notranslate"><span class="pre">cr_self</span> <span class="pre">=</span> <span class="pre">Py_None</span></code>
|
||
(or any other non-NULL value).</p>
|
||
</section>
|
||
<section id="the-name-attribute">
|
||
<h3><a class="toc-backref" href="#the-name-attribute" role="doc-backlink">The __name__ attribute</a></h3>
|
||
<p>The C call protocol requires that the function has a <code class="docutils literal notranslate"><span class="pre">__name__</span></code>
|
||
attribute which is of type <code class="docutils literal notranslate"><span class="pre">str</span></code> (not a subclass).</p>
|
||
<p>Furthermore, the object returned by <code class="docutils literal notranslate"><span class="pre">__name__</span></code> must be stored somewhere;
|
||
it cannot be a temporary object.
|
||
This is required because <code class="docutils literal notranslate"><span class="pre">PyEval_GetFuncName</span></code>
|
||
uses a borrowed reference to the <code class="docutils literal notranslate"><span class="pre">__name__</span></code> attribute
|
||
(see also <a class="footnote-reference brackets" href="#badcapi" id="id1">[2]</a>).</p>
|
||
</section>
|
||
<section id="generic-api-functions">
|
||
<h3><a class="toc-backref" href="#generic-api-functions" role="doc-backlink">Generic API functions</a></h3>
|
||
<p>This section lists the new public API functions or macros
|
||
dealing with the C call protocol.</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">PyCCall_Check(PyObject</span> <span class="pre">*op)</span></code>:
|
||
return true if <code class="docutils literal notranslate"><span class="pre">op</span></code> implements the C call protocol.</li>
|
||
</ul>
|
||
<p>All the functions and macros below
|
||
apply to any instance supporting the C call protocol.
|
||
In other words, <code class="docutils literal notranslate"><span class="pre">PyCCall_Check(func)</span></code> must be true.</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyCCall_Call(PyObject</span> <span class="pre">*func,</span> <span class="pre">PyObject</span> <span class="pre">*args,</span> <span class="pre">PyObject</span> <span class="pre">*kwds)</span></code>:
|
||
call <code class="docutils literal notranslate"><span class="pre">func</span></code> with positional arguments <code class="docutils literal notranslate"><span class="pre">args</span></code>
|
||
and keyword arguments <code class="docutils literal notranslate"><span class="pre">kwds</span></code> (<code class="docutils literal notranslate"><span class="pre">kwds</span></code> may be NULL).
|
||
This function is meant to be put in the <code class="docutils literal notranslate"><span class="pre">tp_call</span></code> slot.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyCCall_FastCall(PyObject</span> <span class="pre">*func,</span> <span class="pre">PyObject</span> <span class="pre">*const</span> <span class="pre">*args,</span> <span class="pre">Py_ssize_t</span> <span class="pre">nargs,</span> <span class="pre">PyObject</span> <span class="pre">*kwds)</span></code>:
|
||
call <code class="docutils literal notranslate"><span class="pre">func</span></code> with <code class="docutils literal notranslate"><span class="pre">nargs</span></code> positional arguments given by <code class="docutils literal notranslate"><span class="pre">args[0]</span></code>, …, <code class="docutils literal notranslate"><span class="pre">args[nargs-1]</span></code>.
|
||
The parameter <code class="docutils literal notranslate"><span class="pre">kwds</span></code> can be NULL (no keyword arguments),
|
||
a dict with <code class="docutils literal notranslate"><span class="pre">name:value</span></code> items or a tuple with keyword names.
|
||
In the latter case, the keyword values are stored in the <code class="docutils literal notranslate"><span class="pre">args</span></code>
|
||
array, starting at <code class="docutils literal notranslate"><span class="pre">args[nargs]</span></code>.</li>
|
||
</ul>
|
||
<p>Macros to access the <code class="docutils literal notranslate"><span class="pre">PyCCallRoot</span></code> and <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structures:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">const</span> <span class="pre">PyCCallRoot</span> <span class="pre">*PyCCall_CCALLROOT(PyObject</span> <span class="pre">*func)</span></code>:
|
||
pointer to the <code class="docutils literal notranslate"><span class="pre">PyCCallRoot</span></code> structure inside <code class="docutils literal notranslate"><span class="pre">func</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">const</span> <span class="pre">PyCCallDef</span> <span class="pre">*PyCCall_CCALLDEF(PyObject</span> <span class="pre">*func)</span></code>:
|
||
shorthand for <code class="docutils literal notranslate"><span class="pre">PyCCall_CCALLROOT(func)->cr_ccall</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">uint32_t</span> <span class="pre">PyCCall_FLAGS(PyObject</span> <span class="pre">*func)</span></code>:
|
||
shorthand for <code class="docutils literal notranslate"><span class="pre">PyCCall_CCALLROOT(func)->cr_ccall->cc_flags</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyCCall_SELF(PyOject</span> <span class="pre">*func)</span></code>:
|
||
shorthand for <code class="docutils literal notranslate"><span class="pre">PyCCall_CCALLROOT(func)->cr_self</span></code>.</li>
|
||
</ul>
|
||
<p>Generic getters, meant to be put into the <code class="docutils literal notranslate"><span class="pre">tp_getset</span></code> array:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyCCall_GenericGetParent(PyObject</span> <span class="pre">*func,</span> <span class="pre">void</span> <span class="pre">*closure)</span></code>:
|
||
return <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code>.
|
||
Raise <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> if <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> is NULL.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyCCall_GenericGetQualname(PyObject</span> <span class="pre">*func,</span> <span class="pre">void</span> <span class="pre">*closure)</span></code>:
|
||
return a string suitable for using as <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code>.
|
||
This uses the <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code> of <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> if possible.
|
||
It also uses the <code class="docutils literal notranslate"><span class="pre">__name__</span></code> attribute.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="profiling">
|
||
<h3><a class="toc-backref" href="#profiling" role="doc-backlink">Profiling</a></h3>
|
||
<p>The profiling events
|
||
<code class="docutils literal notranslate"><span class="pre">c_call</span></code>, <code class="docutils literal notranslate"><span class="pre">c_return</span></code> and <code class="docutils literal notranslate"><span class="pre">c_exception</span></code> are only generated
|
||
when calling actual instances of <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> or <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code>.
|
||
This is done for simplicity and also for backwards compatibility
|
||
(such that the profile function does not receive objects that it does not recognize).
|
||
In a future PEP, we may extend C-level profiling to arbitrary classes
|
||
implementing the C call protocol.</p>
|
||
</section>
|
||
</section>
|
||
<section id="changes-to-built-in-functions-and-methods">
|
||
<h2><a class="toc-backref" href="#changes-to-built-in-functions-and-methods" role="doc-backlink">Changes to built-in functions and methods</a></h2>
|
||
<p>The reference implementation of this PEP changes
|
||
the existing classes <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> and <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code>
|
||
to use the C call protocol.
|
||
In fact, those two classes are almost merged:
|
||
the implementation becomes very similar, but they remain separate classes
|
||
(mostly for backwards compatibility).
|
||
The <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structure is simply stored
|
||
as part of the object structure.
|
||
Both classes use <code class="docutils literal notranslate"><span class="pre">PyCFunctionObject</span></code> as object structure.
|
||
This is the new layout for both classes:</p>
|
||
<div class="highlight-default notranslate" id="pycfunctionobject"><div class="highlight"><pre><span></span><span class="n">typedef</span> <span class="n">struct</span> <span class="p">{</span>
|
||
<span class="n">PyObject_HEAD</span>
|
||
<span class="n">PyCCallDef</span> <span class="o">*</span><span class="n">m_ccall</span><span class="p">;</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">m_self</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Passed</span> <span class="k">as</span> <span class="s1">'self'</span> <span class="n">arg</span> <span class="n">to</span> <span class="n">the</span> <span class="n">C</span> <span class="n">function</span> <span class="o">*/</span>
|
||
<span class="n">PyCCallDef</span> <span class="n">_ccalldef</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Storage</span> <span class="k">for</span> <span class="n">m_ccall</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">m_name</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__name__</span><span class="p">;</span> <span class="nb">str</span> <span class="nb">object</span> <span class="p">(</span><span class="ow">not</span> <span class="n">NULL</span><span class="p">)</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">m_module</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__module__</span><span class="p">;</span> <span class="n">can</span> <span class="n">be</span> <span class="n">anything</span> <span class="o">*/</span>
|
||
<span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">m_doc</span><span class="p">;</span> <span class="o">/*</span> <span class="n">__text_signature__</span> <span class="ow">and</span> <span class="vm">__doc__</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">m_weakreflist</span><span class="p">;</span> <span class="o">/*</span> <span class="n">List</span> <span class="n">of</span> <span class="n">weak</span> <span class="n">references</span> <span class="o">*/</span>
|
||
<span class="p">}</span> <span class="n">PyCFunctionObject</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>For functions of a module and for unbound methods of extension types,
|
||
<code class="docutils literal notranslate"><span class="pre">m_ccall</span></code> points to the <code class="docutils literal notranslate"><span class="pre">_ccalldef</span></code> field.
|
||
For bound methods, <code class="docutils literal notranslate"><span class="pre">m_ccall</span></code> points to the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code>
|
||
of the unbound method.</p>
|
||
<p><strong>NOTE</strong>: the new layout of <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code> changes it
|
||
such that it no longer starts with <code class="docutils literal notranslate"><span class="pre">PyDescr_COMMON</span></code>.
|
||
This is purely an implementation detail and it should cause few (if any)
|
||
compatibility problems.</p>
|
||
<section id="c-api-functions">
|
||
<h3><a class="toc-backref" href="#c-api-functions" role="doc-backlink">C API functions</a></h3>
|
||
<p>The following function is added (also to the <a class="pep reference internal" href="../pep-0384/" title="PEP 384 – Defining a Stable ABI">stable ABI</a>):</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*</span> <span class="pre">PyCFunction_ClsNew(PyTypeObject</span> <span class="pre">*cls,</span> <span class="pre">PyMethodDef</span> <span class="pre">*ml,</span> <span class="pre">PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*module,</span> <span class="pre">PyObject</span> <span class="pre">*parent)</span></code>:
|
||
create a new object with object structure <code class="docutils literal notranslate"><span class="pre">PyCFunctionObject</span></code> and class <code class="docutils literal notranslate"><span class="pre">cls</span></code>.
|
||
The entries of the <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code> structure are used to construct
|
||
the new object, but the pointer to the <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code> structure
|
||
is not stored.
|
||
The flags for the C call protocol are automatically determined in terms
|
||
of <code class="docutils literal notranslate"><span class="pre">ml->ml_flags</span></code>, <code class="docutils literal notranslate"><span class="pre">self</span></code> and <code class="docutils literal notranslate"><span class="pre">parent</span></code>.</li>
|
||
</ul>
|
||
<p>The existing functions <code class="docutils literal notranslate"><span class="pre">PyCFunction_New</span></code>, <code class="docutils literal notranslate"><span class="pre">PyCFunction_NewEx</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">PyDescr_NewMethod</span></code> are implemented in terms of <code class="docutils literal notranslate"><span class="pre">PyCFunction_ClsNew</span></code>.</p>
|
||
<p>The undocumented functions <code class="docutils literal notranslate"><span class="pre">PyCFunction_GetFlags</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">PyCFunction_GET_FLAGS</span></code> are deprecated.
|
||
They are still artificially supported by storing the original <code class="docutils literal notranslate"><span class="pre">METH_...</span></code>
|
||
flags in a bitfield inside <code class="docutils literal notranslate"><span class="pre">cc_flags</span></code>.
|
||
Despite the fact that <code class="docutils literal notranslate"><span class="pre">PyCFunction_GetFlags</span></code> is technically
|
||
part of the <a class="pep reference internal" href="../pep-0384/" title="PEP 384 – Defining a Stable ABI">stable ABI</a>,
|
||
it is highly unlikely to be used that way:
|
||
first of all, it is not even documented.
|
||
Second, the flag <code class="docutils literal notranslate"><span class="pre">METH_FASTCALL</span></code>
|
||
is not part of the stable ABI but it is very common
|
||
(because of Argument Clinic).
|
||
So, if one cannot support <code class="docutils literal notranslate"><span class="pre">METH_FASTCALL</span></code>,
|
||
it is hard to imagine a use case for <code class="docutils literal notranslate"><span class="pre">PyCFunction_GetFlags</span></code>.
|
||
The fact that <code class="docutils literal notranslate"><span class="pre">PyCFunction_GET_FLAGS</span></code> and <code class="docutils literal notranslate"><span class="pre">PyCFunction_GetFlags</span></code>
|
||
are not used at all by CPython outside of <code class="docutils literal notranslate"><span class="pre">Objects/call.c</span></code>
|
||
further shows that these functions are not particularly useful.</p>
|
||
</section>
|
||
</section>
|
||
<section id="inheritance">
|
||
<h2><a class="toc-backref" href="#inheritance" role="doc-backlink">Inheritance</a></h2>
|
||
<p>Extension types inherit the type flag <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_CCALL</span></code>
|
||
and the value <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span></code> from the base class,
|
||
provided that they implement <code class="docutils literal notranslate"><span class="pre">tp_call</span></code> and <code class="docutils literal notranslate"><span class="pre">tp_descr_get</span></code>
|
||
the same way as the base class.
|
||
Heap types never inherit the C call protocol because
|
||
that would not be safe (heap types can be changed dynamically).</p>
|
||
</section>
|
||
<section id="performance">
|
||
<h2><a class="toc-backref" href="#performance" role="doc-backlink">Performance</a></h2>
|
||
<p>This PEP should not impact the performance of existing code
|
||
(in the positive or negative sense).
|
||
It is meant to allow efficient new code to be written,
|
||
not to make existing code faster.</p>
|
||
<p>Here are a few pointers to the <code class="docutils literal notranslate"><span class="pre">python-dev</span></code> mailing list where
|
||
performance improvements are discussed:</p>
|
||
<ul class="simple">
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-July/154571.html">https://mail.python.org/pipermail/python-dev/2018-July/154571.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-July/154740.html">https://mail.python.org/pipermail/python-dev/2018-July/154740.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-July/154775.html">https://mail.python.org/pipermail/python-dev/2018-July/154775.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2019-April/156954.html">https://mail.python.org/pipermail/python-dev/2019-April/156954.html</a></li>
|
||
</ul>
|
||
</section>
|
||
<section id="stable-abi">
|
||
<h2><a class="toc-backref" href="#stable-abi" role="doc-backlink">Stable ABI</a></h2>
|
||
<p>The function <code class="docutils literal notranslate"><span class="pre">PyCFunction_ClsNew</span></code> is added to the <a class="pep reference internal" href="../pep-0384/" title="PEP 384 – Defining a Stable ABI">stable ABI</a>.</p>
|
||
<p>None of the functions, structures or constants dealing with the C call protocol
|
||
are added to the stable ABI.</p>
|
||
<p>There are two reasons for this:
|
||
first of all, the most useful feature of the C call protocol is probably the
|
||
<code class="docutils literal notranslate"><span class="pre">METH_FASTCALL</span></code> calling convention.
|
||
Given that this is not even part of the public API (see also <a class="pep reference internal" href="../pep-0579/" title="PEP 579 – Refactoring C functions and methods">PEP 579</a>, issue 6),
|
||
it would be strange to add anything else from the C call protocol
|
||
to the stable ABI.</p>
|
||
<p>Second, we want the C call protocol to be extensible in the future.
|
||
By not adding anything to the stable ABI,
|
||
we are free to do that without restrictions.</p>
|
||
</section>
|
||
<section id="backwards-compatibility">
|
||
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards compatibility</a></h2>
|
||
<p>There is no difference at all for the Python interface,
|
||
nor for the documented C API
|
||
(in the sense that all functions remain supported with the same functionality).</p>
|
||
<p>The only potential breakage is with C code
|
||
which accesses the internals of <code class="docutils literal notranslate"><span class="pre">PyCFunctionObject</span></code> and <code class="docutils literal notranslate"><span class="pre">PyMethodDescrObject</span></code>.
|
||
We expect very few problems because of this.</p>
|
||
</section>
|
||
<section id="rationale">
|
||
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
||
<section id="why-is-this-better-than-pep-575">
|
||
<h3><a class="toc-backref" href="#why-is-this-better-than-pep-575" role="doc-backlink">Why is this better than PEP 575?</a></h3>
|
||
<p>One of the major complaints of <a class="pep reference internal" href="../pep-0575/" title="PEP 575 – Unifying function/method classes">PEP 575</a> was that is was coupling
|
||
functionality (the calling and introspection protocol)
|
||
with the class hierarchy:
|
||
a class could only benefit from the new features
|
||
if it was a subclass of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>.
|
||
It may be difficult for existing classes to do that
|
||
because they may have other constraints on the layout of the C object structure,
|
||
coming from an existing base class or implementation details.
|
||
For example, <code class="docutils literal notranslate"><span class="pre">functools.lru_cache</span></code> cannot implement <a class="pep reference internal" href="../pep-0575/" title="PEP 575 – Unifying function/method classes">PEP 575</a> as-is.</p>
|
||
<p>It also complicated the implementation precisely because changes
|
||
were needed both in the implementation details and in the class hierarchy.</p>
|
||
<p>The current PEP does not have these problems.</p>
|
||
</section>
|
||
<section id="why-store-the-function-pointer-in-the-instance">
|
||
<h3><a class="toc-backref" href="#why-store-the-function-pointer-in-the-instance" role="doc-backlink">Why store the function pointer in the instance?</a></h3>
|
||
<p>The actual information needed for calling an object
|
||
is stored in the instance (in the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structure)
|
||
instead of the class.
|
||
This is different from the <code class="docutils literal notranslate"><span class="pre">tp_call</span></code> slot or earlier attempts
|
||
at implementing a <code class="docutils literal notranslate"><span class="pre">tp_fastcall</span></code> slot <a class="footnote-reference brackets" href="#bpo29259" id="id2">[1]</a>.</p>
|
||
<p>The main use case is built-in functions and methods.
|
||
For those, the C function to be called does depend on the instance.</p>
|
||
<p>Note that the current protocol makes it easy to support the case
|
||
where the same C function is called for all instances:
|
||
just use a single static <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structure for every instance.</p>
|
||
</section>
|
||
<section id="why-ccall-objclass">
|
||
<h3><a class="toc-backref" href="#why-ccall-objclass" role="doc-backlink">Why CCALL_OBJCLASS?</a></h3>
|
||
<p>The flag <code class="docutils literal notranslate"><span class="pre">CCALL_OBJCLASS</span></code> is meant to support various cases
|
||
where the class of a <code class="docutils literal notranslate"><span class="pre">self</span></code> argument must be checked, such as:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">list</span><span class="o">.</span><span class="n">append</span><span class="p">({},</span> <span class="kc">None</span><span class="p">)</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
|
||
<span class="gr">TypeError</span>: <span class="n">append() requires a 'list' object but received a 'dict'</span>
|
||
|
||
<span class="gp">>>> </span><span class="nb">list</span><span class="o">.</span><span class="fm">__len__</span><span class="p">({})</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
|
||
<span class="gr">TypeError</span>: <span class="n">descriptor '__len__' requires a 'list' object but received a 'dict'</span>
|
||
|
||
<span class="gp">>>> </span><span class="nb">float</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="s2">"fromhex"</span><span class="p">](</span><span class="nb">list</span><span class="p">,</span> <span class="s2">"0xff"</span><span class="p">)</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
|
||
<span class="gr">TypeError</span>: <span class="n">descriptor 'fromhex' for type 'float' doesn't apply to type 'list'</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>In the reference implementation, only the first of these uses the new code.
|
||
The other examples show that these kind of checks appear
|
||
in multiple places, so it makes sense to add generic support for them.</p>
|
||
</section>
|
||
<section id="why-ccall-selfarg">
|
||
<h3><a class="toc-backref" href="#why-ccall-selfarg" role="doc-backlink">Why CCALL_SELFARG?</a></h3>
|
||
<p>The flag <code class="docutils literal notranslate"><span class="pre">CCALL_SELFARG</span></code> and the concept of self slicing
|
||
are needed to support methods:
|
||
the C function should not care
|
||
whether it is called as unbound method or as bound method.
|
||
In both cases, there should be a <code class="docutils literal notranslate"><span class="pre">self</span></code> argument
|
||
and this is simply the first positional argument of an unbound method call.</p>
|
||
<p>For example, <code class="docutils literal notranslate"><span class="pre">list.append</span></code> is a <code class="docutils literal notranslate"><span class="pre">METH_O</span></code> method.
|
||
Both the calls <code class="docutils literal notranslate"><span class="pre">list.append([],</span> <span class="pre">42)</span></code> and <code class="docutils literal notranslate"><span class="pre">[].append(42)</span></code> should
|
||
translate to the C call <code class="docutils literal notranslate"><span class="pre">list_append([],</span> <span class="pre">42)</span></code>.</p>
|
||
<p>Thanks to the proposed C call protocol, we can support this in such a way
|
||
that both the unbound and the bound method share a <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code>
|
||
structure (with the <code class="docutils literal notranslate"><span class="pre">CCALL_SELFARG</span></code> flag set).</p>
|
||
<p>So, <code class="docutils literal notranslate"><span class="pre">CCALL_SELFARG</span></code> has two advantages:
|
||
there is no extra layer of indirection for calling methods
|
||
and constructing bound methods does not require setting up a <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structure.</p>
|
||
<p>Another minor advantage is that we could
|
||
make the error messages for a wrong call signature
|
||
more uniform between Python methods and built-in methods.
|
||
In the following example, Python is undecided whether
|
||
a method takes 1 or 2 arguments:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">class</span> <span class="nc">List</span><span class="p">(</span><span class="nb">list</span><span class="p">):</span>
|
||
<span class="gp">... </span> <span class="k">def</span> <span class="nf">myappend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
|
||
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">List</span><span class="p">()</span><span class="o">.</span><span class="n">myappend</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
|
||
<span class="gr">TypeError</span>: <span class="n">myappend() takes 2 positional arguments but 3 were given</span>
|
||
<span class="gp">>>> </span><span class="n">List</span><span class="p">()</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
|
||
<span class="gr">TypeError</span>: <span class="n">append() takes exactly one argument (2 given)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>It is currently impossible for <code class="docutils literal notranslate"><span class="pre">PyCFunction_Call</span></code>
|
||
to know the actual number of user-visible arguments
|
||
since it cannot distinguish at runtime between
|
||
a function (without <code class="docutils literal notranslate"><span class="pre">self</span></code> argument) and a bound method (with <code class="docutils literal notranslate"><span class="pre">self</span></code> argument).
|
||
The <code class="docutils literal notranslate"><span class="pre">CCALL_SELFARG</span></code> flag makes this difference explicit.</p>
|
||
</section>
|
||
<section id="why-ccall-defarg">
|
||
<h3><a class="toc-backref" href="#why-ccall-defarg" role="doc-backlink">Why CCALL_DEFARG?</a></h3>
|
||
<p>The flag <code class="docutils literal notranslate"><span class="pre">CCALL_DEFARG</span></code> gives the callee access to the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span> <span class="pre">*</span></code>.
|
||
There are various use cases for this:</p>
|
||
<ol class="arabic simple">
|
||
<li>The callee can use the <code class="docutils literal notranslate"><span class="pre">cc_parent</span></code> field, which is useful for <a class="pep reference internal" href="../pep-0573/" title="PEP 573 – Module State Access from C Extension Methods">PEP 573</a>.</li>
|
||
<li>Applications are free to extend the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structure with user-defined
|
||
fields, which can then be accessed analogously.</li>
|
||
<li>In the case where the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> structure
|
||
is part of the object structure
|
||
(this is true for example for <a class="reference internal" href="#pycfunctionobject">PyCFunctionObject</a>),
|
||
an appropriate offset can be subtracted from the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code> pointer
|
||
to get a pointer to the callable object defining that <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span></code>.</li>
|
||
</ol>
|
||
<p>An earlier version of this PEP defined a flag <code class="docutils literal notranslate"><span class="pre">CCALL_FUNCARG</span></code>
|
||
instead of <code class="docutils literal notranslate"><span class="pre">CCALL_DEFARG</span></code> which would pass the callable object
|
||
to the callee.
|
||
This had similar use cases, but there was some ambiguity for
|
||
bound methods: should the “callable object” be the bound method
|
||
object or the original function wrapped by the method?
|
||
By passing the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span> <span class="pre">*</span></code> instead, this ambiguity is gone
|
||
since the bound method uses the <code class="docutils literal notranslate"><span class="pre">PyCCallDef</span> <span class="pre">*</span></code> from the wrapped function.</p>
|
||
</section>
|
||
<section id="replacing-tp-print">
|
||
<h3><a class="toc-backref" href="#replacing-tp-print" role="doc-backlink">Replacing tp_print</a></h3>
|
||
<p>We repurpose <code class="docutils literal notranslate"><span class="pre">tp_print</span></code> as <code class="docutils literal notranslate"><span class="pre">tp_ccalloffset</span></code> because this makes
|
||
it easier for external projects to backport the C call protocol
|
||
to earlier Python versions.
|
||
In particular, the Cython project has shown interest in doing that
|
||
(see <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-June/153927.html">https://mail.python.org/pipermail/python-dev/2018-June/153927.html</a>).</p>
|
||
</section>
|
||
</section>
|
||
<section id="alternative-suggestions">
|
||
<h2><a class="toc-backref" href="#alternative-suggestions" role="doc-backlink">Alternative suggestions</a></h2>
|
||
<p><a class="pep reference internal" href="../pep-0576/" title="PEP 576 – Rationalize Built-in function classes">PEP 576</a> is an alternative approach to solving the same problem as this PEP.
|
||
See <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-July/154238.html">https://mail.python.org/pipermail/python-dev/2018-July/154238.html</a>
|
||
for comments on the difference between <a class="pep reference internal" href="../pep-0576/" title="PEP 576 – Rationalize Built-in function classes">PEP 576</a> and <a class="pep reference internal" href="../pep-0580/" title="PEP 580 – The C call protocol">PEP 580</a>.</p>
|
||
</section>
|
||
<section id="discussion">
|
||
<h2><a class="toc-backref" href="#discussion" role="doc-backlink">Discussion</a></h2>
|
||
<p>Links to threads on the <code class="docutils literal notranslate"><span class="pre">python-dev</span></code> mailing list
|
||
where this PEP has been discussed:</p>
|
||
<ul class="simple">
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-June/153938.html">https://mail.python.org/pipermail/python-dev/2018-June/153938.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-June/153984.html">https://mail.python.org/pipermail/python-dev/2018-June/153984.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-July/154238.html">https://mail.python.org/pipermail/python-dev/2018-July/154238.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-July/154470.html">https://mail.python.org/pipermail/python-dev/2018-July/154470.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-July/154571.html">https://mail.python.org/pipermail/python-dev/2018-July/154571.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-September/155166.html">https://mail.python.org/pipermail/python-dev/2018-September/155166.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-October/155403.html">https://mail.python.org/pipermail/python-dev/2018-October/155403.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2019-March/156853.html">https://mail.python.org/pipermail/python-dev/2019-March/156853.html</a></li>
|
||
<li><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2019-March/156879.html">https://mail.python.org/pipermail/python-dev/2019-March/156879.html</a></li>
|
||
</ul>
|
||
</section>
|
||
<section id="reference-implementation">
|
||
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference implementation</a></h2>
|
||
<p>The reference implementation can be found at
|
||
<a class="reference external" href="https://github.com/jdemeyer/cpython/tree/pep580">https://github.com/jdemeyer/cpython/tree/pep580</a></p>
|
||
<p>For an example of using the C call protocol,
|
||
the following branch implements <code class="docutils literal notranslate"><span class="pre">functools.lru_cache</span></code> using <a class="pep reference internal" href="../pep-0580/" title="PEP 580 – The C call protocol">PEP 580</a>:
|
||
<a class="reference external" href="https://github.com/jdemeyer/cpython/tree/lru580">https://github.com/jdemeyer/cpython/tree/lru580</a></p>
|
||
</section>
|
||
<section id="references">
|
||
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="bpo29259" role="doc-footnote">
|
||
<dt class="label" id="bpo29259">[<a href="#id2">1</a>]</dt>
|
||
<dd>Add tp_fastcall to PyTypeObject: support FASTCALL calling convention for all callable objects,
|
||
<a class="reference external" href="https://bugs.python.org/issue29259">https://bugs.python.org/issue29259</a></aside>
|
||
<aside class="footnote brackets" id="badcapi" role="doc-footnote">
|
||
<dt class="label" id="badcapi">[<a href="#id1">2</a>]</dt>
|
||
<dd>Bad C API,
|
||
<a class="reference external" href="https://pythoncapi.readthedocs.io/bad_api.html#bad-c-api">https://pythoncapi.readthedocs.io/bad_api.html#bad-c-api</a></aside>
|
||
</aside>
|
||
</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-0580.rst">https://github.com/python/peps/blob/main/peps/pep-0580.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0580.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="#rejection-notice">Rejection Notice</a></li>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a></li>
|
||
<li><a class="reference internal" href="#overview">Overview</a></li>
|
||
<li><a class="reference internal" href="#new-data-structures">New data structures</a><ul>
|
||
<li><a class="reference internal" href="#parent">Parent</a></li>
|
||
<li><a class="reference internal" href="#using-tp-print">Using tp_print</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#the-c-call-protocol">The C call protocol</a><ul>
|
||
<li><a class="reference internal" href="#checking-objclass">Checking __objclass__</a></li>
|
||
<li><a class="reference internal" href="#self-slicing">Self slicing</a></li>
|
||
<li><a class="reference internal" href="#descriptor-behavior">Descriptor behavior</a></li>
|
||
<li><a class="reference internal" href="#the-name-attribute">The __name__ attribute</a></li>
|
||
<li><a class="reference internal" href="#generic-api-functions">Generic API functions</a></li>
|
||
<li><a class="reference internal" href="#profiling">Profiling</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#changes-to-built-in-functions-and-methods">Changes to built-in functions and methods</a><ul>
|
||
<li><a class="reference internal" href="#c-api-functions">C API functions</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#inheritance">Inheritance</a></li>
|
||
<li><a class="reference internal" href="#performance">Performance</a></li>
|
||
<li><a class="reference internal" href="#stable-abi">Stable ABI</a></li>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards compatibility</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
|
||
<li><a class="reference internal" href="#why-is-this-better-than-pep-575">Why is this better than PEP 575?</a></li>
|
||
<li><a class="reference internal" href="#why-store-the-function-pointer-in-the-instance">Why store the function pointer in the instance?</a></li>
|
||
<li><a class="reference internal" href="#why-ccall-objclass">Why CCALL_OBJCLASS?</a></li>
|
||
<li><a class="reference internal" href="#why-ccall-selfarg">Why CCALL_SELFARG?</a></li>
|
||
<li><a class="reference internal" href="#why-ccall-defarg">Why CCALL_DEFARG?</a></li>
|
||
<li><a class="reference internal" href="#replacing-tp-print">Replacing tp_print</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#alternative-suggestions">Alternative suggestions</a></li>
|
||
<li><a class="reference internal" href="#discussion">Discussion</a></li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference implementation</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-0580.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> |