1213 lines
127 KiB
HTML
1213 lines
127 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 575 – Unifying function/method classes | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0575/">
|
||
<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 575 – Unifying function/method classes | peps.python.org'>
|
||
<meta property="og:description" content="Reorganize the class hierarchy for functions and methods with the goal of reducing the difference between built-in functions (implemented in C) and Python functions. Mainly, make built-in functions behave more like Python functions without sacrificing p...">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0575/">
|
||
<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="Reorganize the class hierarchy for functions and methods with the goal of reducing the difference between built-in functions (implemented in C) and Python functions. Mainly, make built-in functions behave more like Python functions without sacrificing p...">
|
||
<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 575</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 575 – Unifying function/method classes</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">Status<span class="colon">:</span></dt>
|
||
<dd class="field-even"><abbr title="Removed from consideration by sponsor or authors">Withdrawn</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">27-Mar-2018</dd>
|
||
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-odd">3.8</dd>
|
||
<dt class="field-even">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-even">31-Mar-2018, 12-Apr-2018, 27-Apr-2018, 05-May-2018</dd>
|
||
</dl>
|
||
<hr class="docutils" />
|
||
<section id="contents">
|
||
<details><summary>Table of Contents</summary><ul class="simple">
|
||
<li><a class="reference internal" href="#withdrawal-notice">Withdrawal 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="#new-classes">New classes</a><ul>
|
||
<li><a class="reference internal" href="#base-function">base_function</a></li>
|
||
<li><a class="reference internal" href="#cfunction">cfunction</a></li>
|
||
<li><a class="reference internal" href="#defined-function">defined_function</a></li>
|
||
<li><a class="reference internal" href="#function">function</a></li>
|
||
<li><a class="reference internal" href="#bound-method">bound_method</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#calling-base-function-instances">Calling base_function instances</a><ul>
|
||
<li><a class="reference internal" href="#checking-objclass">Checking __objclass__</a></li>
|
||
<li><a class="reference internal" href="#flags">Flags</a></li>
|
||
<li><a class="reference internal" href="#self-slicing">Self slicing</a></li>
|
||
<li><a class="reference internal" href="#meth-pass-function">METH_PASS_FUNCTION</a></li>
|
||
<li><a class="reference internal" href="#meth-fastcall">METH_FASTCALL</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#automatic-creation-of-built-in-functions">Automatic creation of built-in functions</a><ul>
|
||
<li><a class="reference internal" href="#unbound-methods-of-extension-types">Unbound methods of extension types</a></li>
|
||
<li><a class="reference internal" href="#built-in-functions-of-a-module">Built-in functions of a module</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#further-changes">Further changes</a><ul>
|
||
<li><a class="reference internal" href="#new-type-flag">New type flag</a></li>
|
||
<li><a class="reference internal" href="#c-api-functions">C API functions</a></li>
|
||
<li><a class="reference internal" href="#changes-to-the-types-module">Changes to the types module</a></li>
|
||
<li><a class="reference internal" href="#changes-to-the-inspect-module">Changes to the inspect module</a></li>
|
||
<li><a class="reference internal" href="#profiling">Profiling</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#non-cpython-implementations">Non-CPython implementations</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
|
||
<li><a class="reference internal" href="#why-not-simply-change-existing-classes">Why not simply change existing classes?</a></li>
|
||
<li><a class="reference internal" href="#why-text-signature-is-not-a-solution">Why __text_signature__ is not a solution</a></li>
|
||
<li><a class="reference internal" href="#defined-function-versus-function">defined_function versus function</a></li>
|
||
<li><a class="reference internal" href="#scope-of-this-pep-which-classes-are-involved">Scope of this PEP: which classes are involved?</a></li>
|
||
<li><a class="reference internal" href="#not-treating-meth-static-and-meth-class">Not treating METH_STATIC and METH_CLASS</a></li>
|
||
<li><a class="reference internal" href="#self-in-base-function">__self__ in base_function</a></li>
|
||
<li><a class="reference internal" href="#two-implementations-of-doc">Two implementations of __doc__</a></li>
|
||
<li><a class="reference internal" href="#subclassing">Subclassing</a></li>
|
||
<li><a class="reference internal" href="#replacing-tp-call-meth-pass-function-and-meth-call-unbound">Replacing tp_call: METH_PASS_FUNCTION and METH_CALL_UNBOUND</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards compatibility</a><ul>
|
||
<li><a class="reference internal" href="#changes-to-types-and-inspect">Changes to types and inspect</a></li>
|
||
<li><a class="reference internal" href="#python-functions">Python functions</a></li>
|
||
<li><a class="reference internal" href="#id7">Built-in functions of a module</a></li>
|
||
<li><a class="reference internal" href="#built-in-bound-and-unbound-methods">Built-in bound and unbound methods</a></li>
|
||
<li><a class="reference internal" href="#new-attributes">New attributes</a></li>
|
||
<li><a class="reference internal" href="#method-descriptor-and-pydescr-newmethod">method_descriptor and PyDescr_NewMethod</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#two-phase-implementation">Two-phase Implementation</a><ul>
|
||
<li><a class="reference internal" href="#phase-one-keep-existing-classes-but-add-base-classes">Phase one: keep existing classes but add base classes</a></li>
|
||
<li><a class="reference internal" href="#phase-two">Phase two</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
|
||
<li><a class="reference internal" href="#appendix-current-situation">Appendix: current situation</a><ul>
|
||
<li><a class="reference internal" href="#builtin-function-or-method-built-in-functions-and-bound-methods">builtin_function_or_method: built-in functions and bound methods</a></li>
|
||
<li><a class="reference internal" href="#method-descriptor-built-in-unbound-methods">method_descriptor: built-in unbound methods</a></li>
|
||
<li><a class="reference internal" href="#function-python-functions">function: Python functions</a></li>
|
||
<li><a class="reference internal" href="#method-python-bound-methods">method: Python bound methods</a></li>
|
||
</ul>
|
||
</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="withdrawal-notice">
|
||
<h2><a class="toc-backref" href="#withdrawal-notice" role="doc-backlink">Withdrawal notice</a></h2>
|
||
<p>See <a class="pep reference internal" href="../pep-0580/" title="PEP 580 – The C call protocol">PEP 580</a> for a better solution to allowing fast calling of custom classes.</p>
|
||
<p>See <a class="pep reference internal" href="../pep-0579/" title="PEP 579 – Refactoring C functions and methods">PEP 579</a> for a broader discussion of some of the other issues from this PEP.</p>
|
||
</section>
|
||
<section id="abstract">
|
||
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
||
<p>Reorganize the class hierarchy for functions and methods
|
||
with the goal of reducing the difference between
|
||
built-in functions (implemented in C) and Python functions.
|
||
Mainly, make built-in functions behave more like Python functions
|
||
without sacrificing performance.</p>
|
||
<p>A new base class <code class="docutils literal notranslate"><span class="pre">base_function</span></code> is introduced and the various function
|
||
classes, as well as <code class="docutils literal notranslate"><span class="pre">method</span></code> (renamed to <code class="docutils literal notranslate"><span class="pre">bound_method</span></code>), inherit from it.</p>
|
||
<p>We also allow subclassing the Python <code class="docutils literal notranslate"><span class="pre">function</span></code> class.</p>
|
||
</section>
|
||
<section id="motivation">
|
||
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
||
<p>Currently, CPython has two different function classes:
|
||
the first is Python functions, which is what you get
|
||
when defining a function with <code class="docutils literal notranslate"><span class="pre">def</span></code> or <code class="docutils literal notranslate"><span class="pre">lambda</span></code>.
|
||
The second is built-in functions such as <code class="docutils literal notranslate"><span class="pre">len</span></code>, <code class="docutils literal notranslate"><span class="pre">isinstance</span></code> or <code class="docutils literal notranslate"><span class="pre">numpy.dot</span></code>.
|
||
These are implemented in C.</p>
|
||
<p>These two classes are implemented completely independently and have different functionality.
|
||
In particular, it is currently not possible to implement a function efficiently in C
|
||
(only built-in functions can do that)
|
||
while still allowing introspection like <code class="docutils literal notranslate"><span class="pre">inspect.signature</span></code> or <code class="docutils literal notranslate"><span class="pre">inspect.getsourcefile</span></code>
|
||
(only Python functions can do that).
|
||
This is a problem for projects like Cython <a class="footnote-reference brackets" href="#cython" id="id1">[1]</a> that want to do exactly that.</p>
|
||
<p>In Cython, this was worked around by inventing a new function class called <code class="docutils literal notranslate"><span class="pre">cyfunction</span></code>.
|
||
Unfortunately, a new function class creates problems:
|
||
the <code class="docutils literal notranslate"><span class="pre">inspect</span></code> module does not recognize such functions as being functions <a class="footnote-reference brackets" href="#bpo30071" id="id2">[2]</a>
|
||
and the performance is worse
|
||
(CPython has specific optimizations for calling built-in functions).</p>
|
||
<p>A second motivation is more generally making built-in functions and methods
|
||
behave more like Python functions and methods.
|
||
For example, Python unbound methods are just functions but
|
||
unbound methods of extension types (e.g. <code class="docutils literal notranslate"><span class="pre">dict.get</span></code>) are a distinct class.
|
||
Bound methods of Python classes have a <code class="docutils literal notranslate"><span class="pre">__func__</span></code> attribute,
|
||
bound methods of extension types do not.</p>
|
||
<p>Third, this PEP allows great customization of functions.
|
||
The <code class="docutils literal notranslate"><span class="pre">function</span></code> class becomes subclassable and custom function
|
||
subclasses are also allowed for functions implemented in C.
|
||
In the latter case, this can be done with the same performance
|
||
as true built-in functions.
|
||
All functions can access the function object
|
||
(the <code class="docutils literal notranslate"><span class="pre">self</span></code> in <code class="docutils literal notranslate"><span class="pre">__call__</span></code>), paving the way for <a class="pep reference internal" href="../pep-0573/" title="PEP 573 – Module State Access from C Extension Methods">PEP 573</a>.</p>
|
||
</section>
|
||
<section id="new-classes">
|
||
<h2><a class="toc-backref" href="#new-classes" role="doc-backlink">New classes</a></h2>
|
||
<p>This is the new class hierarchy for functions and methods:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="nb">object</span>
|
||
<span class="o">|</span>
|
||
<span class="o">|</span>
|
||
<span class="n">base_function</span>
|
||
<span class="o">/</span> <span class="o">|</span> \
|
||
<span class="o">/</span> <span class="o">|</span> \
|
||
<span class="o">/</span> <span class="o">|</span> <span class="n">defined_function</span>
|
||
<span class="o">/</span> <span class="o">|</span> \
|
||
<span class="n">cfunction</span> <span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="o">|</span> \
|
||
<span class="o">|</span> <span class="n">function</span>
|
||
<span class="o">|</span>
|
||
<span class="n">bound_method</span> <span class="p">(</span><span class="o">*</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The two classes marked with (*) do <em>not</em> allow subclassing;
|
||
the others do.</p>
|
||
<p>There is no difference between functions and unbound methods,
|
||
while bound methods are instances of <code class="docutils literal notranslate"><span class="pre">bound_method</span></code>.</p>
|
||
<section id="base-function">
|
||
<h3><a class="toc-backref" href="#base-function" role="doc-backlink">base_function</a></h3>
|
||
<p>The class <code class="docutils literal notranslate"><span class="pre">base_function</span></code> becomes a new base class for all function types.
|
||
It is based on the existing <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> class,
|
||
but with the following differences and new features:</p>
|
||
<ol class="arabic simple">
|
||
<li>It acts as a descriptor implementing <code class="docutils literal notranslate"><span class="pre">__get__</span></code> to turn a function into a method
|
||
if <code class="docutils literal notranslate"><span class="pre">m_self</span></code> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.
|
||
If <code class="docutils literal notranslate"><span class="pre">m_self</span></code> is not <code class="docutils literal notranslate"><span class="pre">NULL</span></code>,
|
||
then this is a no-op: the existing function is returned instead.</li>
|
||
<li>A new read-only attribute <code class="docutils literal notranslate"><span class="pre">__parent__</span></code>, represented in the C structure as <code class="docutils literal notranslate"><span class="pre">m_parent</span></code>.
|
||
If this attribute exists, it represents the defining object.
|
||
For methods of extension types, this is the defining class (<code class="docutils literal notranslate"><span class="pre">__class__</span></code> in plain Python)
|
||
and for functions of a module, this is the defining module.
|
||
In general, it can be any Python object.
|
||
If <code class="docutils literal notranslate"><span class="pre">__parent__</span></code> is a class, it carries special semantics:
|
||
in that case, the function must be called with <code class="docutils literal notranslate"><span class="pre">self</span></code> being an instance of that class.
|
||
Finally, <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code> and <code class="docutils literal notranslate"><span class="pre">__reduce__</span></code> will use <code class="docutils literal notranslate"><span class="pre">__parent__</span></code>
|
||
as namespace (instead of <code class="docutils literal notranslate"><span class="pre">__self__</span></code> before).</li>
|
||
<li>A new attribute <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code> which equals <code class="docutils literal notranslate"><span class="pre">__parent__</span></code> if <code class="docutils literal notranslate"><span class="pre">__parent__</span></code>
|
||
is a class. Otherwise, accessing <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code> raises <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code>.
|
||
This is meant to be backwards compatible with <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code>.</li>
|
||
<li>The field <code class="docutils literal notranslate"><span class="pre">ml_doc</span></code> and the attributes <code class="docutils literal notranslate"><span class="pre">__doc__</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">__text_signature__</span></code> (see <a class="pep reference internal" href="../pep-0436/" title="PEP 436 – The Argument Clinic DSL">Argument Clinic</a>)
|
||
are not supported.</li>
|
||
<li>A new flag <code class="docutils literal notranslate"><span class="pre">METH_PASS_FUNCTION</span></code> for <code class="docutils literal notranslate"><span class="pre">ml_flags</span></code>.
|
||
If this flag is set, the C function stored in <code class="docutils literal notranslate"><span class="pre">ml_meth</span></code> is called with
|
||
an additional first argument equal to the function object.</li>
|
||
<li>A new flag <code class="docutils literal notranslate"><span class="pre">METH_BINDING</span></code> for <code class="docutils literal notranslate"><span class="pre">ml_flags</span></code> which only applies to
|
||
functions of a module (not methods of a class).
|
||
If this flag is set, then <code class="docutils literal notranslate"><span class="pre">m_self</span></code> is set to <code class="docutils literal notranslate"><span class="pre">NULL</span></code> instead
|
||
of the module.
|
||
This allows the function to behave more like a Python function
|
||
as it enables <code class="docutils literal notranslate"><span class="pre">__get__</span></code>.</li>
|
||
<li>A new flag <code class="docutils literal notranslate"><span class="pre">METH_CALL_UNBOUND</span></code> to disable <a class="reference internal" href="#self-slicing">self slicing</a>.</li>
|
||
<li>A new flag <code class="docutils literal notranslate"><span class="pre">METH_PYTHON</span></code> for <code class="docutils literal notranslate"><span class="pre">ml_flags</span></code>.
|
||
This flag indicates that this function should be treated as Python function.
|
||
Ideally, use of this flag should be avoided because it goes
|
||
against the duck typing philosophy.
|
||
It is still needed in a few places though, for example <a class="reference internal" href="#profiling">profiling</a>.</li>
|
||
</ol>
|
||
<p>The goal of <code class="docutils literal notranslate"><span class="pre">base_function</span></code> is that it supports all different ways
|
||
of calling functions and methods in just one structure.
|
||
For example, the new flag <code class="docutils literal notranslate"><span class="pre">METH_PASS_FUNCTION</span></code>
|
||
will be used by the implementation of methods.</p>
|
||
<p>It is not possible to directly create instances of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>
|
||
(<code class="docutils literal notranslate"><span class="pre">tp_new</span></code> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>).
|
||
However, it is legal for C code to manually create instances.</p>
|
||
<p>These are the relevant C structures:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyTypeObject</span> <span class="n">PyBaseFunction_Type</span><span class="p">;</span>
|
||
|
||
<span class="n">typedef</span> <span class="n">struct</span> <span class="p">{</span>
|
||
<span class="n">PyObject_HEAD</span>
|
||
<span class="n">PyCFunctionDef</span> <span class="o">*</span><span class="n">m_ml</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Description</span> <span class="n">of</span> <span class="n">the</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">m_self</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__self__</span><span class="p">:</span> <span class="n">anything</span><span class="p">,</span> <span class="n">can</span> <span class="n">be</span> <span class="n">NULL</span><span class="p">;</span> <span class="n">readonly</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">anything</span> <span class="p">(</span><span class="n">typically</span> <span class="nb">str</span><span class="p">)</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">m_parent</span><span class="p">;</span> <span class="o">/*</span> <span class="n">__parent__</span><span class="p">:</span> <span class="n">anything</span><span class="p">,</span> <span class="n">can</span> <span class="n">be</span> <span class="n">NULL</span><span class="p">;</span> <span class="n">readonly</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">PyBaseFunctionObject</span><span class="p">;</span>
|
||
|
||
<span class="n">typedef</span> <span class="n">struct</span> <span class="p">{</span>
|
||
<span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">ml_name</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="n">name</span> <span class="n">of</span> <span class="n">the</span> <span class="n">built</span><span class="o">-</span><span class="ow">in</span> <span class="n">function</span><span class="o">/</span><span class="n">method</span> <span class="o">*/</span>
|
||
<span class="n">PyCFunction</span> <span class="n">ml_meth</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="n">C</span> <span class="n">function</span> <span class="n">that</span> <span class="n">implements</span> <span class="n">it</span> <span class="o">*/</span>
|
||
<span class="nb">int</span> <span class="n">ml_flags</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Combination</span> <span class="n">of</span> <span class="n">METH_xxx</span> <span class="n">flags</span><span class="p">,</span> <span class="n">which</span> <span class="n">mostly</span>
|
||
<span class="n">describe</span> <span class="n">the</span> <span class="n">args</span> <span class="n">expected</span> <span class="n">by</span> <span class="n">the</span> <span class="n">C</span> <span class="n">func</span> <span class="o">*/</span>
|
||
<span class="p">}</span> <span class="n">PyCFunctionDef</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Subclasses may extend <code class="docutils literal notranslate"><span class="pre">PyCFunctionDef</span></code> with extra fields.</p>
|
||
<p>The Python attribute <code class="docutils literal notranslate"><span class="pre">__self__</span></code> returns <code class="docutils literal notranslate"><span class="pre">m_self</span></code>,
|
||
except if <code class="docutils literal notranslate"><span class="pre">METH_STATIC</span></code> is set.
|
||
In that case or if <code class="docutils literal notranslate"><span class="pre">m_self</span></code> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>,
|
||
then there is no <code class="docutils literal notranslate"><span class="pre">__self__</span></code> attribute at all.
|
||
For that reason, we write either <code class="docutils literal notranslate"><span class="pre">m_self</span></code> or <code class="docutils literal notranslate"><span class="pre">__self__</span></code> in this PEP
|
||
with slightly different meanings.</p>
|
||
</section>
|
||
<section id="cfunction">
|
||
<h3><a class="toc-backref" href="#cfunction" role="doc-backlink">cfunction</a></h3>
|
||
<p>This is the new version of the old <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> class.
|
||
The name <code class="docutils literal notranslate"><span class="pre">cfunction</span></code> was chosen to avoid confusion with “built-in”
|
||
in the sense of “something in the <code class="docutils literal notranslate"><span class="pre">builtins</span></code> module”.
|
||
It also fits better with the C API which use the <code class="docutils literal notranslate"><span class="pre">PyCFunction</span></code> prefix.</p>
|
||
<p>The class <code class="docutils literal notranslate"><span class="pre">cfunction</span></code> is a copy of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>, with the following differences:</p>
|
||
<ol class="arabic">
|
||
<li><code class="docutils literal notranslate"><span class="pre">m_ml</span></code> points to a <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code> structure,
|
||
extending <code class="docutils literal notranslate"><span class="pre">PyCFunctionDef</span></code> with an additional <code class="docutils literal notranslate"><span class="pre">ml_doc</span></code>
|
||
field to implement <code class="docutils literal notranslate"><span class="pre">__doc__</span></code> and <code class="docutils literal notranslate"><span class="pre">__text_signature__</span></code>
|
||
as read-only attributes:<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">char</span> <span class="o">*</span><span class="n">ml_name</span><span class="p">;</span>
|
||
<span class="n">PyCFunction</span> <span class="n">ml_meth</span><span class="p">;</span>
|
||
<span class="nb">int</span> <span class="n">ml_flags</span><span class="p">;</span>
|
||
<span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">ml_doc</span><span class="p">;</span>
|
||
<span class="p">}</span> <span class="n">PyMethodDef</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code> is part of the <a class="pep reference internal" href="../pep-0384/" title="PEP 384 – Defining a Stable ABI">Python Stable ABI</a>
|
||
and it is used by practically all extension modules,
|
||
so we absolutely cannot change this structure.</p>
|
||
</li>
|
||
<li><a class="pep reference internal" href="../pep-0436/" title="PEP 436 – The Argument Clinic DSL">Argument Clinic</a> is supported.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">__self__</span></code> always exists. In the cases where <code class="docutils literal notranslate"><span class="pre">base_function.__self__</span></code>
|
||
would raise <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code>, instead <code class="docutils literal notranslate"><span class="pre">None</span></code> is returned.</li>
|
||
</ol>
|
||
<p>The type object is <code class="docutils literal notranslate"><span class="pre">PyTypeObject</span> <span class="pre">PyCFunction_Type</span></code>
|
||
and we define <code class="docutils literal notranslate"><span class="pre">PyCFunctionObject</span></code> as alias of <code class="docutils literal notranslate"><span class="pre">PyBaseFunctionObject</span></code>
|
||
(except for the type of <code class="docutils literal notranslate"><span class="pre">m_ml</span></code>).</p>
|
||
</section>
|
||
<section id="defined-function">
|
||
<h3><a class="toc-backref" href="#defined-function" role="doc-backlink">defined_function</a></h3>
|
||
<p>The class <code class="docutils literal notranslate"><span class="pre">defined_function</span></code> is an abstract base class meant
|
||
to indicate that the function has introspection support.
|
||
Instances of <code class="docutils literal notranslate"><span class="pre">defined_function</span></code> are required to support all attributes
|
||
that Python functions have, namely
|
||
<code class="docutils literal notranslate"><span class="pre">__code__</span></code>, <code class="docutils literal notranslate"><span class="pre">__globals__</span></code>, <code class="docutils literal notranslate"><span class="pre">__doc__</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">__defaults__</span></code>, <code class="docutils literal notranslate"><span class="pre">__kwdefaults__</span></code>, <code class="docutils literal notranslate"><span class="pre">__closure__</span></code> and <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>.
|
||
There is also a <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> to support attributes added by the user.</p>
|
||
<p>None of these is required to be meaningful.
|
||
In particular, <code class="docutils literal notranslate"><span class="pre">__code__</span></code> may not be a working code object,
|
||
possibly only a few fields may be filled in.
|
||
This PEP does not dictate how the various attributes are implemented.
|
||
They may be simple struct members or more complicated descriptors.
|
||
Only read-only support is required, none of the attributes is required to be writable.</p>
|
||
<p>The class <code class="docutils literal notranslate"><span class="pre">defined_function</span></code> is mainly meant for auto-generated C code,
|
||
for example produced by Cython <a class="footnote-reference brackets" href="#cython" id="id3">[1]</a>.
|
||
There is no API to create instances of it.</p>
|
||
<p>The C structure is the following:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyTypeObject</span> <span class="n">PyDefinedFunction_Type</span><span class="p">;</span>
|
||
|
||
<span class="n">typedef</span> <span class="n">struct</span> <span class="p">{</span>
|
||
<span class="n">PyBaseFunctionObject</span> <span class="n">base</span><span class="p">;</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_dict</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__dict__</span><span class="p">:</span> <span class="nb">dict</span> <span class="ow">or</span> <span class="n">NULL</span> <span class="o">*/</span>
|
||
<span class="p">}</span> <span class="n">PyDefinedFunctionObject</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
<p><strong>TODO</strong>: maybe find a better name for <code class="docutils literal notranslate"><span class="pre">defined_function</span></code>.
|
||
Other proposals: <code class="docutils literal notranslate"><span class="pre">inspect_function</span></code> (anything that satisfies <code class="docutils literal notranslate"><span class="pre">inspect.isfunction</span></code>),
|
||
<code class="docutils literal notranslate"><span class="pre">builtout_function</span></code> (a function that is better built out; pun on builtin),
|
||
<code class="docutils literal notranslate"><span class="pre">generic_function</span></code> (original proposal but conflicts with <code class="docutils literal notranslate"><span class="pre">functools.singledispatch</span></code> generic functions),
|
||
<code class="docutils literal notranslate"><span class="pre">user_function</span></code> (defined by the user as opposed to CPython).</p>
|
||
</section>
|
||
<section id="function">
|
||
<h3><a class="toc-backref" href="#function" role="doc-backlink">function</a></h3>
|
||
<p>This is the class meant for functions implemented in Python.
|
||
Unlike the other function types,
|
||
instances of <code class="docutils literal notranslate"><span class="pre">function</span></code> can be created from Python code.
|
||
This is not changed, so we do not describe the details in this PEP.</p>
|
||
<p>The layout of the C structure is the following:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyTypeObject</span> <span class="n">PyFunction_Type</span><span class="p">;</span>
|
||
|
||
<span class="n">typedef</span> <span class="n">struct</span> <span class="p">{</span>
|
||
<span class="n">PyBaseFunctionObject</span> <span class="n">base</span><span class="p">;</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_dict</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__dict__</span><span class="p">:</span> <span class="nb">dict</span> <span class="ow">or</span> <span class="n">NULL</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_code</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__code__</span><span class="p">:</span> <span class="n">code</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_globals</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__globals__</span><span class="p">:</span> <span class="nb">dict</span><span class="p">;</span> <span class="n">readonly</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_name</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__name__</span><span class="p">:</span> <span class="n">string</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_qualname</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__qualname__</span><span class="p">:</span> <span class="n">string</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_doc</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__doc__</span><span class="p">:</span> <span class="n">can</span> <span class="n">be</span> <span class="n">anything</span> <span class="ow">or</span> <span class="n">NULL</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_defaults</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__defaults__</span><span class="p">:</span> <span class="nb">tuple</span> <span class="ow">or</span> <span class="n">NULL</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_kwdefaults</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__kwdefaults__</span><span class="p">:</span> <span class="nb">dict</span> <span class="ow">or</span> <span class="n">NULL</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_closure</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__closure__</span><span class="p">:</span> <span class="nb">tuple</span> <span class="n">of</span> <span class="n">cell</span> <span class="n">objects</span> <span class="ow">or</span> <span class="n">NULL</span><span class="p">;</span> <span class="n">readonly</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_annotations</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__annotations__</span><span class="p">:</span> <span class="nb">dict</span> <span class="ow">or</span> <span class="n">NULL</span> <span class="o">*/</span>
|
||
<span class="n">PyCFunctionDef</span> <span class="n">_ml</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Storage</span> <span class="k">for</span> <span class="n">base</span><span class="o">.</span><span class="n">m_ml</span> <span class="o">*/</span>
|
||
<span class="p">}</span> <span class="n">PyFunctionObject</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The descriptor <code class="docutils literal notranslate"><span class="pre">__name__</span></code> returns <code class="docutils literal notranslate"><span class="pre">func_name</span></code>.
|
||
When setting <code class="docutils literal notranslate"><span class="pre">__name__</span></code>, also <code class="docutils literal notranslate"><span class="pre">base.m_ml->ml_name</span></code> is updated
|
||
with the UTF-8 encoded name.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">_ml</span></code> field reserves space to be used by <code class="docutils literal notranslate"><span class="pre">base.m_ml</span></code>.</p>
|
||
<p>A <code class="docutils literal notranslate"><span class="pre">base_function</span></code> instance must have the flag <code class="docutils literal notranslate"><span class="pre">METH_PYTHON</span></code> set
|
||
if and only if it is an instance of <code class="docutils literal notranslate"><span class="pre">function</span></code>.</p>
|
||
<p>When constructing an instance of <code class="docutils literal notranslate"><span class="pre">function</span></code> from <code class="docutils literal notranslate"><span class="pre">code</span></code> and <code class="docutils literal notranslate"><span class="pre">globals</span></code>,
|
||
an instance is created with <code class="docutils literal notranslate"><span class="pre">base.m_ml</span> <span class="pre">=</span> <span class="pre">&_ml</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">base.m_self</span> <span class="pre">=</span> <span class="pre">NULL</span></code>.</p>
|
||
<p>To make subclassing easier, we also add a copy constructor:
|
||
if <code class="docutils literal notranslate"><span class="pre">f</span></code> is an instance of <code class="docutils literal notranslate"><span class="pre">function</span></code>, then <code class="docutils literal notranslate"><span class="pre">types.FunctionType(f)</span></code> copies <code class="docutils literal notranslate"><span class="pre">f</span></code>.
|
||
This conveniently allows using a custom function type as decorator:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">types</span> <span class="kn">import</span> <span class="n">FunctionType</span>
|
||
<span class="gp">>>> </span><span class="k">class</span> <span class="nc">CustomFunction</span><span class="p">(</span><span class="n">FunctionType</span><span class="p">):</span>
|
||
<span class="gp">... </span> <span class="k">pass</span>
|
||
<span class="gp">>>> </span><span class="nd">@CustomFunction</span>
|
||
<span class="gp">... </span><span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
|
||
<span class="gp">... </span> <span class="k">return</span> <span class="n">x</span>
|
||
<span class="gp">>>> </span><span class="nb">type</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||
<span class="go"><class '__main__.CustomFunction'></span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This also removes many use cases of <code class="docutils literal notranslate"><span class="pre">functools.wraps</span></code>:
|
||
wrappers can be replaced by subclasses of <code class="docutils literal notranslate"><span class="pre">function</span></code>.</p>
|
||
</section>
|
||
<section id="bound-method">
|
||
<h3><a class="toc-backref" href="#bound-method" role="doc-backlink">bound_method</a></h3>
|
||
<p>The class <code class="docutils literal notranslate"><span class="pre">bound_method</span></code> is used for all bound methods,
|
||
regardless of the class of the underlying function.
|
||
It adds one new attribute on top of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>:
|
||
<code class="docutils literal notranslate"><span class="pre">__func__</span></code> points to that function.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">bound_method</span></code> replaces the old <code class="docutils literal notranslate"><span class="pre">method</span></code> class
|
||
which was used only for Python functions bound as method.</p>
|
||
<p>There is a complication because we want to allow
|
||
constructing a method from an arbitrary callable.
|
||
This may be an already-bound method or simply not an instance of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>.
|
||
Therefore, in practice there are two kinds of methods:</p>
|
||
<ul class="simple">
|
||
<li>For arbitrary callables, we use a single fixed <code class="docutils literal notranslate"><span class="pre">PyCFunctionDef</span></code>
|
||
structure with the <code class="docutils literal notranslate"><span class="pre">METH_PASS_FUNCTION</span></code> flag set.</li>
|
||
<li>For methods which bind instances of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>
|
||
(more precisely, which have the <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_BASEFUNCTION</span></code> flag set)
|
||
that have <a class="reference internal" href="#self-slicing">self slicing</a>,
|
||
we instead use the <code class="docutils literal notranslate"><span class="pre">PyCFunctionDef</span></code> from the original function.
|
||
This way, we don’t lose any performance when calling bound methods.
|
||
In this case, the <code class="docutils literal notranslate"><span class="pre">__func__</span></code> attribute is only used to implement
|
||
various attributes but not for calling the method.</li>
|
||
</ul>
|
||
<p>When constructing a new method from a <code class="docutils literal notranslate"><span class="pre">base_function</span></code>,
|
||
we check that the <code class="docutils literal notranslate"><span class="pre">self</span></code> object is an instance of <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code>
|
||
(if a class was specified as parent) and raise a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> otherwise.</p>
|
||
<p>The C structure is:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PyTypeObject</span> <span class="n">PyMethod_Type</span><span class="p">;</span>
|
||
|
||
<span class="n">typedef</span> <span class="n">struct</span> <span class="p">{</span>
|
||
<span class="n">PyBaseFunctionObject</span> <span class="n">base</span><span class="p">;</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">im_func</span><span class="p">;</span> <span class="o">/*</span> <span class="vm">__func__</span><span class="p">:</span> <span class="n">function</span> <span class="n">implementing</span> <span class="n">the</span> <span class="n">method</span><span class="p">;</span> <span class="n">readonly</span> <span class="o">*/</span>
|
||
<span class="p">}</span> <span class="n">PyMethodObject</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="calling-base-function-instances">
|
||
<h2><a class="toc-backref" href="#calling-base-function-instances" role="doc-backlink">Calling base_function instances</a></h2>
|
||
<p>We specify the implementation of <code class="docutils literal notranslate"><span class="pre">__call__</span></code> for instances of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>.</p>
|
||
<section id="checking-objclass">
|
||
<h3><a class="toc-backref" href="#checking-objclass" role="doc-backlink">Checking __objclass__</a></h3>
|
||
<p>First of all, a type check is done if the <code class="docutils literal notranslate"><span class="pre">__parent__</span></code> of the function
|
||
is a class
|
||
(recall that <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code> then becomes an alias of <code class="docutils literal notranslate"><span class="pre">__parent__</span></code>):
|
||
if <code class="docutils literal notranslate"><span class="pre">m_self</span></code> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code> (this is the case for unbound methods of extension types),
|
||
then 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">__objclass__</span></code>.
|
||
If not, a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> is raised.</p>
|
||
<p>Note that bound methods have <code class="docutils literal notranslate"><span class="pre">m_self</span> <span class="pre">!=</span> <span class="pre">NULL</span></code>, so the <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code>
|
||
is not checked.
|
||
Instead, the <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code> check is done when constructing the method.</p>
|
||
</section>
|
||
<section id="flags">
|
||
<h3><a class="toc-backref" href="#flags" role="doc-backlink">Flags</a></h3>
|
||
<p>For convenience, we define a new constant:
|
||
<code class="docutils literal notranslate"><span class="pre">METH_CALLFLAGS</span></code> combines all flags from <code class="docutils literal notranslate"><span class="pre">PyCFunctionDef.ml_flags</span></code>
|
||
which specify the signature of the C function to be called.
|
||
It is equal to</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">METH_VARARGS</span> <span class="o">|</span> <span class="n">METH_FASTCALL</span> <span class="o">|</span> <span class="n">METH_NOARGS</span> <span class="o">|</span> <span class="n">METH_O</span> <span class="o">|</span> <span class="n">METH_KEYWORDS</span> <span class="o">|</span> <span class="n">METH_PASS_FUNCTION</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Exactly one of the first four flags above must be set
|
||
and only <code class="docutils literal notranslate"><span class="pre">METH_VARARGS</span></code> and <code class="docutils literal notranslate"><span class="pre">METH_FASTCALL</span></code> may be combined with <code class="docutils literal notranslate"><span class="pre">METH_KEYWORDS</span></code>.
|
||
Violating these rules is undefined behaviour.</p>
|
||
<p>There are one new flags which affects calling functions,
|
||
namely <code class="docutils literal notranslate"><span class="pre">METH_PASS_FUNCTION</span></code> and <code class="docutils literal notranslate"><span class="pre">METH_CALL_UNBOUND</span></code>.
|
||
Some flags are already documented in <a class="footnote-reference brackets" href="#methoddoc" id="id4">[5]</a>.
|
||
We explain the others below.</p>
|
||
</section>
|
||
<section id="self-slicing">
|
||
<h3><a class="toc-backref" href="#self-slicing" role="doc-backlink">Self slicing</a></h3>
|
||
<p>If the function has <code class="docutils literal notranslate"><span class="pre">m_self</span> <span class="pre">==</span> <span class="pre">NULL</span></code> and the flag <code class="docutils literal notranslate"><span class="pre">METH_CALL_UNBOUND</span></code>
|
||
is not set, then the first positional argument (if any)
|
||
is removed from <code class="docutils literal notranslate"><span class="pre">*args</span></code> and instead passed as first argument to the C function.
|
||
Effectively, the first positional argument is treated as <code class="docutils literal notranslate"><span class="pre">__self__</span></code>.
|
||
This is meant to support unbound methods
|
||
such that the C function does not see the difference
|
||
between bound and unbound method calls.
|
||
This does not affect keyword arguments in any way.</p>
|
||
<p>This process is called <em>self slicing</em> and a function is said to
|
||
<em>have self slicing</em> if <code class="docutils literal notranslate"><span class="pre">m_self</span> <span class="pre">==</span> <span class="pre">NULL</span></code> and <code class="docutils literal notranslate"><span class="pre">METH_CALL_UNBOUND</span></code> is not set.</p>
|
||
<p>Note that a <code class="docutils literal notranslate"><span class="pre">METH_NOARGS</span></code> function which has 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">METH_O</span></code> function with self slicing has two arguments.</p>
|
||
</section>
|
||
<section id="meth-pass-function">
|
||
<h3><a class="toc-backref" href="#meth-pass-function" role="doc-backlink">METH_PASS_FUNCTION</a></h3>
|
||
<p>If this flag is set, then the C function is called with an
|
||
additional first argument, namely the function itself
|
||
(the <code class="docutils literal notranslate"><span class="pre">base_function</span></code> instance).
|
||
As special case, if the function is a <code class="docutils literal notranslate"><span class="pre">bound_method</span></code>,
|
||
then the underlying function of the method is passed
|
||
(but not recursively: if a <code class="docutils literal notranslate"><span class="pre">bound_method</span></code> wraps a <code class="docutils literal notranslate"><span class="pre">bound_method</span></code>,
|
||
then <code class="docutils literal notranslate"><span class="pre">__func__</span></code> is only applied once).</p>
|
||
<p>For example, an ordinary <code class="docutils literal notranslate"><span class="pre">METH_VARARGS</span></code> function has signature
|
||
<code class="docutils literal notranslate"><span class="pre">(PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*args)</span></code>.
|
||
With <code class="docutils literal notranslate"><span class="pre">METH_VARARGS</span> <span class="pre">|</span> <span class="pre">METH_PASS_FUNCTION</span></code>, this becomes
|
||
<code class="docutils literal notranslate"><span class="pre">(PyObject</span> <span class="pre">*func,</span> <span class="pre">PyObject</span> <span class="pre">*self,</span> <span class="pre">PyObject</span> <span class="pre">*args)</span></code>.</p>
|
||
</section>
|
||
<section id="meth-fastcall">
|
||
<h3><a class="toc-backref" href="#meth-fastcall" role="doc-backlink">METH_FASTCALL</a></h3>
|
||
<p>This is an existing but undocumented flag.
|
||
We suggest to officially support and document it.</p>
|
||
<p>If the flag <code class="docutils literal notranslate"><span class="pre">METH_FASTCALL</span></code> is set without <code class="docutils literal notranslate"><span class="pre">METH_KEYWORDS</span></code>,
|
||
then the <code class="docutils literal notranslate"><span class="pre">ml_meth</span></code> field is of type <code class="docutils literal notranslate"><span class="pre">PyCFunctionFast</span></code>
|
||
which takes the arguments <code class="docutils literal notranslate"><span class="pre">(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>.
|
||
Such a function takes only positional arguments and they are passed as plain C array
|
||
<code class="docutils literal notranslate"><span class="pre">args</span></code> of length <code class="docutils literal notranslate"><span class="pre">nargs</span></code>.</p>
|
||
<p>If the flags <code class="docutils literal notranslate"><span class="pre">METH_FASTCALL</span> <span class="pre">|</span> <span class="pre">METH_KEYWORDS</span></code> are set,
|
||
then the <code class="docutils literal notranslate"><span class="pre">ml_meth</span></code> field is of type <code class="docutils literal notranslate"><span class="pre">PyCFunctionFastKeywords</span></code>
|
||
which takes the arguments <code class="docutils literal notranslate"><span class="pre">(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>.
|
||
The positional arguments are passed as C array <code class="docutils literal notranslate"><span class="pre">args</span></code> of length <code class="docutils literal notranslate"><span class="pre">nargs</span></code>.
|
||
The <em>values</em> of the keyword arguments follow in that array,
|
||
starting at position <code class="docutils literal notranslate"><span class="pre">nargs</span></code>.
|
||
The <em>keys</em> (names) of the keyword arguments are passed as a <code class="docutils literal notranslate"><span class="pre">tuple</span></code> in <code class="docutils literal notranslate"><span class="pre">kwnames</span></code>.
|
||
As an example, assume that 3 positional and 2 keyword arguments are given.
|
||
Then <code class="docutils literal notranslate"><span class="pre">args</span></code> is an array of length 3 + 2 = 5, <code class="docutils literal notranslate"><span class="pre">nargs</span></code> equals 3 and <code class="docutils literal notranslate"><span class="pre">kwnames</span></code> is a 2-tuple.</p>
|
||
</section>
|
||
</section>
|
||
<section id="automatic-creation-of-built-in-functions">
|
||
<h2><a class="toc-backref" href="#automatic-creation-of-built-in-functions" role="doc-backlink">Automatic creation of built-in functions</a></h2>
|
||
<p>Python automatically generates instances of <code class="docutils literal notranslate"><span class="pre">cfunction</span></code>
|
||
for extension types (using the <code class="docutils literal notranslate"><span class="pre">PyTypeObject.tp_methods</span></code> field) and modules
|
||
(using the <code class="docutils literal notranslate"><span class="pre">PyModuleDef.m_methods</span></code> field).
|
||
The arrays <code class="docutils literal notranslate"><span class="pre">PyTypeObject.tp_methods</span></code> and <code class="docutils literal notranslate"><span class="pre">PyModuleDef.m_methods</span></code>
|
||
must be arrays of <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code> structures.</p>
|
||
<section id="unbound-methods-of-extension-types">
|
||
<h3><a class="toc-backref" href="#unbound-methods-of-extension-types" role="doc-backlink">Unbound methods of extension types</a></h3>
|
||
<p>The type of unbound methods changes from <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code>
|
||
to <code class="docutils literal notranslate"><span class="pre">cfunction</span></code>.
|
||
The object which appears as unbound method is the same object which
|
||
appears in the class <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>.
|
||
Python automatically sets the <code class="docutils literal notranslate"><span class="pre">__parent__</span></code> attribute to the defining class.</p>
|
||
</section>
|
||
<section id="built-in-functions-of-a-module">
|
||
<h3><a class="toc-backref" href="#built-in-functions-of-a-module" role="doc-backlink">Built-in functions of a module</a></h3>
|
||
<p>For the case of functions of a module,
|
||
<code class="docutils literal notranslate"><span class="pre">__parent__</span></code> will be set to the module.
|
||
Unless the flag <code class="docutils literal notranslate"><span class="pre">METH_BINDING</span></code> is given, also <code class="docutils literal notranslate"><span class="pre">__self__</span></code>
|
||
will be set to the module (for backwards compatibility).</p>
|
||
<p>An important consequence is that such functions by default
|
||
do not become methods when used as attribute
|
||
(<code class="docutils literal notranslate"><span class="pre">base_function.__get__</span></code> only does that if <code class="docutils literal notranslate"><span class="pre">m_self</span></code> was <code class="docutils literal notranslate"><span class="pre">NULL</span></code>).
|
||
One could consider this a bug, but this was done for backwards compatibility reasons:
|
||
in an initial post on python-ideas <a class="footnote-reference brackets" href="#proposal" id="id5">[6]</a> the consensus was to keep this
|
||
misfeature of built-in functions.</p>
|
||
<p>However, to allow this anyway for specific or newly implemented
|
||
built-in functions, the <code class="docutils literal notranslate"><span class="pre">METH_BINDING</span></code> flag prevents setting <code class="docutils literal notranslate"><span class="pre">__self__</span></code>.</p>
|
||
</section>
|
||
</section>
|
||
<section id="further-changes">
|
||
<h2><a class="toc-backref" href="#further-changes" role="doc-backlink">Further changes</a></h2>
|
||
<section id="new-type-flag">
|
||
<h3><a class="toc-backref" href="#new-type-flag" role="doc-backlink">New type flag</a></h3>
|
||
<p>A new <code class="docutils literal notranslate"><span class="pre">PyTypeObject</span></code> flag (for <code class="docutils literal notranslate"><span class="pre">tp_flags</span></code>) is added:
|
||
<code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_BASEFUNCTION</span></code> to indicate that instances of this type are
|
||
functions which can be called and bound as method like a <code class="docutils literal notranslate"><span class="pre">base_function</span></code>.</p>
|
||
<p>This is different from flags like <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_LIST_SUBCLASS</span></code>
|
||
because it indicates more than just a subclass:
|
||
it also indicates a default implementation of <code class="docutils literal notranslate"><span class="pre">__call__</span></code> and <code class="docutils literal notranslate"><span class="pre">__get__</span></code>.
|
||
In particular, such subclasses of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>
|
||
must follow the implementation from the section <a class="reference internal" href="#calling-base-function-instances">Calling base_function instances</a>.</p>
|
||
<p>This flag is automatically set for extension types which
|
||
inherit the <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> implementation from <code class="docutils literal notranslate"><span class="pre">base_function</span></code>.
|
||
Extension types can explicitly specify it if they
|
||
override <code class="docutils literal notranslate"><span class="pre">__call__</span></code> or <code class="docutils literal notranslate"><span class="pre">__get__</span></code> in a compatible way.
|
||
The flag <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_BASEFUNCTION</span></code> must never be set for a heap type
|
||
because that would not be safe (heap types can be changed dynamically).</p>
|
||
</section>
|
||
<section id="c-api-functions">
|
||
<h3><a class="toc-backref" href="#c-api-functions" role="doc-backlink">C API functions</a></h3>
|
||
<p>We list some relevant Python/C API macros and functions.
|
||
Some of these are existing (possibly changed) functions, some are new:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">PyBaseFunction_CheckFast(PyObject</span> <span class="pre">*op)</span></code>: return true if <code class="docutils literal notranslate"><span class="pre">op</span></code>
|
||
is an instance of a class with the <code class="docutils literal notranslate"><span class="pre">Py_TPFLAGS_BASEFUNCTION</span></code> set.
|
||
This is the function that you need to use to determine
|
||
whether it is meaningful to access the <code class="docutils literal notranslate"><span class="pre">base_function</span></code> internals.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">PyBaseFunction_Check(PyObject</span> <span class="pre">*op)</span></code>: return true if <code class="docutils literal notranslate"><span class="pre">op</span></code>
|
||
is an instance of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyBaseFunction_New(PyTypeObject</span> <span class="pre">*cls,</span> <span class="pre">PyCFunctionDef</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 instance of <code class="docutils literal notranslate"><span class="pre">cls</span></code> (which must be a subclass of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>)
|
||
from the given data.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">PyCFunction_Check(PyObject</span> <span class="pre">*op)</span></code>: return true if <code class="docutils literal notranslate"><span class="pre">op</span></code>
|
||
is an instance of <code class="docutils literal notranslate"><span class="pre">cfunction</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">PyCFunction_NewEx(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></code>:
|
||
create a new instance of <code class="docutils literal notranslate"><span class="pre">cfunction</span></code>.
|
||
As special case, if <code class="docutils literal notranslate"><span class="pre">self</span></code> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>,
|
||
then set <code class="docutils literal notranslate"><span class="pre">self</span> <span class="pre">=</span> <span class="pre">Py_None</span></code> instead (for backwards compatibility).
|
||
If <code class="docutils literal notranslate"><span class="pre">self</span></code> is a module, then <code class="docutils literal notranslate"><span class="pre">__parent__</span></code> is set to <code class="docutils literal notranslate"><span class="pre">self</span></code>.
|
||
Otherwise, <code class="docutils literal notranslate"><span class="pre">__parent__</span></code> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</li>
|
||
<li>For many existing <code class="docutils literal notranslate"><span class="pre">PyCFunction_...</span></code> and <code class="docutils literal notranslate"><span class="pre">PyMethod_</span></code> functions,
|
||
we define a new function <code class="docutils literal notranslate"><span class="pre">PyBaseFunction_...</span></code>
|
||
acting on <code class="docutils literal notranslate"><span class="pre">base_function</span></code> instances.
|
||
The old functions are kept as aliases of the new functions.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">PyFunction_Check(PyObject</span> <span class="pre">*op)</span></code>: return true if <code class="docutils literal notranslate"><span class="pre">op</span></code>
|
||
is an instance of <code class="docutils literal notranslate"><span class="pre">base_function</span></code> with the <code class="docutils literal notranslate"><span class="pre">METH_PYTHON</span></code> flag set
|
||
(this is equivalent to checking whether <code class="docutils literal notranslate"><span class="pre">op</span></code> is an instance of <code class="docutils literal notranslate"><span class="pre">function</span></code>).</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">PyFunction_CheckFast(PyObject</span> <span class="pre">*op)</span></code>: equivalent to
|
||
<code class="docutils literal notranslate"><span class="pre">PyFunction_Check(op)</span> <span class="pre">&&</span> <span class="pre">PyBaseFunction_CheckFast(op)</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">PyFunction_CheckExact(PyObject</span> <span class="pre">*op)</span></code>: return true
|
||
if the type of <code class="docutils literal notranslate"><span class="pre">op</span></code> is <code class="docutils literal notranslate"><span class="pre">function</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyFunction_NewPython(PyTypeObject</span> <span class="pre">*cls,</span> <span class="pre">PyObject</span> <span class="pre">*code,</span> <span class="pre">PyObject</span> <span class="pre">*globals,</span> <span class="pre">PyObject</span> <span class="pre">*name,</span> <span class="pre">PyObject</span> <span class="pre">*qualname)</span></code>:
|
||
create a new instance of <code class="docutils literal notranslate"><span class="pre">cls</span></code> (which must be a subclass of <code class="docutils literal notranslate"><span class="pre">function</span></code>)
|
||
from the given data.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyFunction_New(PyObject</span> <span class="pre">*code,</span> <span class="pre">PyObject</span> <span class="pre">*globals)</span></code>:
|
||
create a new instance of <code class="docutils literal notranslate"><span class="pre">function</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyFunction_NewWithQualName(PyObject</span> <span class="pre">*code,</span> <span class="pre">PyObject</span> <span class="pre">*globals,</span> <span class="pre">PyObject</span> <span class="pre">*qualname)</span></code>:
|
||
create a new instance of <code class="docutils literal notranslate"><span class="pre">function</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*PyFunction_Copy(PyTypeObject</span> <span class="pre">*cls,</span> <span class="pre">PyObject</span> <span class="pre">*func)</span></code>:
|
||
create a new instance of <code class="docutils literal notranslate"><span class="pre">cls</span></code> (which must be a subclass of <code class="docutils literal notranslate"><span class="pre">function</span></code>)
|
||
by copying a given <code class="docutils literal notranslate"><span class="pre">function</span></code>.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="changes-to-the-types-module">
|
||
<h3><a class="toc-backref" href="#changes-to-the-types-module" role="doc-backlink">Changes to the types module</a></h3>
|
||
<p>Two types are added: <code class="docutils literal notranslate"><span class="pre">types.BaseFunctionType</span></code> corresponding to
|
||
<code class="docutils literal notranslate"><span class="pre">base_function</span></code> and <code class="docutils literal notranslate"><span class="pre">types.DefinedFunctionType</span></code> corresponding to
|
||
<code class="docutils literal notranslate"><span class="pre">defined_function</span></code>.</p>
|
||
<p>Apart from that, no changes to the <code class="docutils literal notranslate"><span class="pre">types</span></code> module are made.
|
||
In particular, <code class="docutils literal notranslate"><span class="pre">types.FunctionType</span></code> refers to <code class="docutils literal notranslate"><span class="pre">function</span></code>.
|
||
However, the actual types will change:
|
||
in particular, <code class="docutils literal notranslate"><span class="pre">types.BuiltinFunctionType</span></code> will no longer be the same
|
||
as <code class="docutils literal notranslate"><span class="pre">types.BuiltinMethodType</span></code>.</p>
|
||
</section>
|
||
<section id="changes-to-the-inspect-module">
|
||
<h3><a class="toc-backref" href="#changes-to-the-inspect-module" role="doc-backlink">Changes to the inspect module</a></h3>
|
||
<p>The new function <code class="docutils literal notranslate"><span class="pre">inspect.isbasefunction</span></code> checks for an instance of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">inspect.isfunction</span></code> checks for an instance of <code class="docutils literal notranslate"><span class="pre">defined_function</span></code>.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">inspect.isbuiltin</span></code> checks for an instance of <code class="docutils literal notranslate"><span class="pre">cfunction</span></code>.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">inspect.isroutine</span></code> checks <code class="docutils literal notranslate"><span class="pre">isbasefunction</span></code> or <code class="docutils literal notranslate"><span class="pre">ismethoddescriptor</span></code>.</p>
|
||
<p><strong>NOTE</strong>: bpo-33261 <a class="footnote-reference brackets" href="#bpo33261" id="id6">[3]</a> should be fixed first.</p>
|
||
</section>
|
||
<section id="profiling">
|
||
<h3><a class="toc-backref" href="#profiling" role="doc-backlink">Profiling</a></h3>
|
||
<p>Currently, <code class="docutils literal notranslate"><span class="pre">sys.setprofile</span></code> supports <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>
|
||
events for built-in functions.
|
||
These events are generated when calling or returning from a built-in function.
|
||
By contrast, the <code class="docutils literal notranslate"><span class="pre">call</span></code> and <code class="docutils literal notranslate"><span class="pre">return</span></code> events are generated by the function itself.
|
||
So nothing needs to change for the <code class="docutils literal notranslate"><span class="pre">call</span></code> and <code class="docutils literal notranslate"><span class="pre">return</span></code> events.</p>
|
||
<p>Since we no longer make a difference between C functions and Python functions,
|
||
we need to prevent the <code class="docutils literal notranslate"><span class="pre">c_*</span></code> events for Python functions.
|
||
This is done by not generating those events if the
|
||
<code class="docutils literal notranslate"><span class="pre">METH_PYTHON</span></code> flag in <code class="docutils literal notranslate"><span class="pre">ml_flags</span></code> is set.</p>
|
||
</section>
|
||
</section>
|
||
<section id="non-cpython-implementations">
|
||
<h2><a class="toc-backref" href="#non-cpython-implementations" role="doc-backlink">Non-CPython implementations</a></h2>
|
||
<p>Most of this PEP is only relevant to CPython.
|
||
For other implementations of Python,
|
||
the two changes that are required are the <code class="docutils literal notranslate"><span class="pre">base_function</span></code> base class
|
||
and the fact that <code class="docutils literal notranslate"><span class="pre">function</span></code> can be subclassed.
|
||
The classes <code class="docutils literal notranslate"><span class="pre">cfunction</span></code> and <code class="docutils literal notranslate"><span class="pre">defined_function</span></code> are not required.</p>
|
||
<p>We require <code class="docutils literal notranslate"><span class="pre">base_function</span></code> for consistency but we put no requirements on it:
|
||
it is acceptable if this is just a copy of <code class="docutils literal notranslate"><span class="pre">object</span></code>.
|
||
Support for the new <code class="docutils literal notranslate"><span class="pre">__parent__</span></code> (and <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code>) attribute is not required.
|
||
If there is no <code class="docutils literal notranslate"><span class="pre">defined_function</span></code> class,
|
||
then <code class="docutils literal notranslate"><span class="pre">types.DefinedFunctionType</span></code> should be an alias of <code class="docutils literal notranslate"><span class="pre">types.FunctionType</span></code>.</p>
|
||
</section>
|
||
<section id="rationale">
|
||
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
||
<section id="why-not-simply-change-existing-classes">
|
||
<h3><a class="toc-backref" href="#why-not-simply-change-existing-classes" role="doc-backlink">Why not simply change existing classes?</a></h3>
|
||
<p>One could try to solve the problem by keeping the existing classes
|
||
without introducing a new <code class="docutils literal notranslate"><span class="pre">base_function</span></code> class.</p>
|
||
<p>That might look like a simpler solution but it is not:
|
||
it would require introspection support for 3 distinct classes:
|
||
<code class="docutils literal notranslate"><span class="pre">function</span></code>, <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>.
|
||
For the latter two classes, “introspection support” would mean
|
||
at a minimum allowing subclassing.
|
||
But we don’t want to lose performance, so we want fast subclass checks.
|
||
This would require two new flags in <code class="docutils literal notranslate"><span class="pre">tp_flags</span></code>.
|
||
And we want subclasses to allow <code class="docutils literal notranslate"><span class="pre">__get__</span></code> for built-in functions,
|
||
so we should implement the <code class="docutils literal notranslate"><span class="pre">LOAD_METHOD</span></code> opcode for built-in functions too.
|
||
More generally, a lot of functionality would need to be duplicated
|
||
and the end result would be far more complex code.</p>
|
||
<p>It is also not clear how the introspection of built-in function subclasses
|
||
would interact with <code class="docutils literal notranslate"><span class="pre">__text_signature__</span></code>.
|
||
Having two independent kinds of <code class="docutils literal notranslate"><span class="pre">inspect.signature</span></code> support on the same
|
||
class sounds like asking for problems.</p>
|
||
<p>And this would not fix some of the other differences between built-in functions
|
||
and Python functions that were mentioned in the <a class="reference internal" href="#motivation">motivation</a>.</p>
|
||
</section>
|
||
<section id="why-text-signature-is-not-a-solution">
|
||
<h3><a class="toc-backref" href="#why-text-signature-is-not-a-solution" role="doc-backlink">Why __text_signature__ is not a solution</a></h3>
|
||
<p>Built-in functions have an attribute <code class="docutils literal notranslate"><span class="pre">__text_signature__</span></code>,
|
||
which gives the signature of the function as plain text.
|
||
The default values are evaluated by <code class="docutils literal notranslate"><span class="pre">ast.literal_eval</span></code>.
|
||
Because of this, it supports only a small number of standard Python classes
|
||
and not arbitrary Python objects.</p>
|
||
<p>And even if <code class="docutils literal notranslate"><span class="pre">__text_signature__</span></code> would allow arbitrary signatures somehow,
|
||
that is only one piece of introspection:
|
||
it does not help with <code class="docutils literal notranslate"><span class="pre">inspect.getsourcefile</span></code> for example.</p>
|
||
</section>
|
||
<section id="defined-function-versus-function">
|
||
<h3><a class="toc-backref" href="#defined-function-versus-function" role="doc-backlink">defined_function versus function</a></h3>
|
||
<p>In many places, a decision needs to be made whether the old <code class="docutils literal notranslate"><span class="pre">function</span></code> class
|
||
should be replaced by <code class="docutils literal notranslate"><span class="pre">defined_function</span></code> or the new <code class="docutils literal notranslate"><span class="pre">function</span></code> class.
|
||
This is done by thinking of the most likely use case:</p>
|
||
<ol class="arabic simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">types.FunctionType</span></code> refers to <code class="docutils literal notranslate"><span class="pre">function</span></code> because that
|
||
type might be used to construct instances using <code class="docutils literal notranslate"><span class="pre">types.FunctionType(...)</span></code>.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">inspect.isfunction()</span></code> refers to <code class="docutils literal notranslate"><span class="pre">defined_function</span></code>
|
||
because this is the class where introspection is supported.</li>
|
||
<li>The C API functions must refer to <code class="docutils literal notranslate"><span class="pre">function</span></code> because
|
||
we do not specify how the various attributes of <code class="docutils literal notranslate"><span class="pre">defined_function</span></code>
|
||
are implemented.
|
||
We expect that this is not a problem since there is typically no
|
||
reason for introspection to be done by C extensions.</li>
|
||
</ol>
|
||
</section>
|
||
<section id="scope-of-this-pep-which-classes-are-involved">
|
||
<h3><a class="toc-backref" href="#scope-of-this-pep-which-classes-are-involved" role="doc-backlink">Scope of this PEP: which classes are involved?</a></h3>
|
||
<p>The main motivation of this PEP is fixing function classes,
|
||
so we certainly want to unify 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">function</span></code>.</p>
|
||
<p>Since built-in functions and methods have the same class,
|
||
it seems natural to include bound methods too.
|
||
And since there are no “unbound methods” for Python functions,
|
||
it makes sense to get rid of unbound methods for extension types.</p>
|
||
<p>For now, no changes are made to the classes <code class="docutils literal notranslate"><span class="pre">staticmethod</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">classmethod</span></code> and <code class="docutils literal notranslate"><span class="pre">classmethod_descriptor</span></code>.
|
||
It would certainly make sense to put these in the <code class="docutils literal notranslate"><span class="pre">base_function</span></code>
|
||
class hierarchy and unify <code class="docutils literal notranslate"><span class="pre">classmethod</span></code> and <code class="docutils literal notranslate"><span class="pre">classmethod_descriptor</span></code>.
|
||
However, this PEP is already big enough
|
||
and this is left as a possible future improvement.</p>
|
||
<p>Slot wrappers for extension types like <code class="docutils literal notranslate"><span class="pre">__init__</span></code> or <code class="docutils literal notranslate"><span class="pre">__eq__</span></code>
|
||
are quite different from normal methods.
|
||
They are also typically not called directly because you would normally
|
||
write <code class="docutils literal notranslate"><span class="pre">foo[i]</span></code> instead of <code class="docutils literal notranslate"><span class="pre">foo.__getitem__(i)</span></code>.
|
||
So these are left outside the scope of this PEP.</p>
|
||
<p>Python also has an <code class="docutils literal notranslate"><span class="pre">instancemethod</span></code> class,
|
||
which seems to be a relic from Python 2,
|
||
where it was used for bound and unbound methods.
|
||
It is not clear whether there is still a use case for it.
|
||
In any case, there is no reason to deal with it in this PEP.</p>
|
||
<p><strong>TODO</strong>: should <code class="docutils literal notranslate"><span class="pre">instancemethod</span></code> be deprecated?
|
||
It doesn’t seem used at all within CPython 3.7,
|
||
but maybe external packages use it?</p>
|
||
</section>
|
||
<section id="not-treating-meth-static-and-meth-class">
|
||
<h3><a class="toc-backref" href="#not-treating-meth-static-and-meth-class" role="doc-backlink">Not treating METH_STATIC and METH_CLASS</a></h3>
|
||
<p>Almost nothing in this PEP refers to the flags <code class="docutils literal notranslate"><span class="pre">METH_STATIC</span></code> and <code class="docutils literal notranslate"><span class="pre">METH_CLASS</span></code>.
|
||
These flags are checked only by the <a class="reference internal" href="#automatic-creation-of-built-in-functions">automatic creation of built-in functions</a>.
|
||
When a <code class="docutils literal notranslate"><span class="pre">staticmethod</span></code>, <code class="docutils literal notranslate"><span class="pre">classmethod</span></code> or <code class="docutils literal notranslate"><span class="pre">classmethod_descriptor</span></code>
|
||
is bound (i.e. <code class="docutils literal notranslate"><span class="pre">__get__</span></code> is called),
|
||
a <code class="docutils literal notranslate"><span class="pre">base_function</span></code> instance is created with <code class="docutils literal notranslate"><span class="pre">m_self</span> <span class="pre">!=</span> <span class="pre">NULL</span></code>.
|
||
For a <code class="docutils literal notranslate"><span class="pre">classmethod</span></code>, this is obvious since <code class="docutils literal notranslate"><span class="pre">m_self</span></code>
|
||
is the class that the method is bound to.
|
||
For a <code class="docutils literal notranslate"><span class="pre">staticmethod</span></code>, one can take an arbitrary Python object for <code class="docutils literal notranslate"><span class="pre">m_self</span></code>.
|
||
For backwards compatibility, we choose <code class="docutils literal notranslate"><span class="pre">m_self</span> <span class="pre">=</span> <span class="pre">__parent__</span></code> for static methods
|
||
of extension types.</p>
|
||
</section>
|
||
<section id="self-in-base-function">
|
||
<h3><a class="toc-backref" href="#self-in-base-function" role="doc-backlink">__self__ in base_function</a></h3>
|
||
<p>It may look strange at first sight to add the <code class="docutils literal notranslate"><span class="pre">__self__</span></code> slot
|
||
in <code class="docutils literal notranslate"><span class="pre">base_function</span></code> as opposed to <code class="docutils literal notranslate"><span class="pre">bound_method</span></code>.
|
||
We took this idea from the existing <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> class.
|
||
It allows us to have a single general implementation of <code class="docutils literal notranslate"><span class="pre">__call__</span></code> and <code class="docutils literal notranslate"><span class="pre">__get__</span></code>
|
||
for the various function classes discussed in this PEP.</p>
|
||
<p>It also makes it easy to support existing built-in functions
|
||
which set <code class="docutils literal notranslate"><span class="pre">__self__</span></code> to the module (for example, <code class="docutils literal notranslate"><span class="pre">sys.exit.__self__</span></code> is <code class="docutils literal notranslate"><span class="pre">sys</span></code>).</p>
|
||
</section>
|
||
<section id="two-implementations-of-doc">
|
||
<h3><a class="toc-backref" href="#two-implementations-of-doc" role="doc-backlink">Two implementations of __doc__</a></h3>
|
||
<p><code class="docutils literal notranslate"><span class="pre">base_function</span></code> does not support function docstrings.
|
||
Instead, the classes <code class="docutils literal notranslate"><span class="pre">cfunction</span></code> and <code class="docutils literal notranslate"><span class="pre">function</span></code>
|
||
each have their own way of dealing with docstrings
|
||
(and <code class="docutils literal notranslate"><span class="pre">bound_method</span></code> just takes the <code class="docutils literal notranslate"><span class="pre">__doc__</span></code> from the wrapped function).</p>
|
||
<p>For <code class="docutils literal notranslate"><span class="pre">cfunction</span></code>, the docstring is stored (together with the text signature)
|
||
as C string in the read-only <code class="docutils literal notranslate"><span class="pre">ml_doc</span></code> field of a <code class="docutils literal notranslate"><span class="pre">PyMethodDef</span></code>.
|
||
For <code class="docutils literal notranslate"><span class="pre">function</span></code>, the docstring is stored as a writable Python object
|
||
and it does not actually need to be a string.
|
||
It looks hard to unify these two very different ways of dealing with <code class="docutils literal notranslate"><span class="pre">__doc__</span></code>.
|
||
For backwards compatibility, we keep the existing implementations.</p>
|
||
<p>For <code class="docutils literal notranslate"><span class="pre">defined_function</span></code>, we require <code class="docutils literal notranslate"><span class="pre">__doc__</span></code> to be implemented
|
||
but we do not specify how. A subclass can implement <code class="docutils literal notranslate"><span class="pre">__doc__</span></code> the
|
||
same way as <code class="docutils literal notranslate"><span class="pre">cfunction</span></code> or using a struct member or some other way.</p>
|
||
</section>
|
||
<section id="subclassing">
|
||
<h3><a class="toc-backref" href="#subclassing" role="doc-backlink">Subclassing</a></h3>
|
||
<p>We disallow subclassing of <code class="docutils literal notranslate"><span class="pre">cfunction</span></code> and <code class="docutils literal notranslate"><span class="pre">bound_method</span></code>
|
||
to enable fast type checks for <code class="docutils literal notranslate"><span class="pre">PyCFunction_Check</span></code> and <code class="docutils literal notranslate"><span class="pre">PyMethod_Check</span></code>.</p>
|
||
<p>We allow subclassing of the other classes because there is no reason to disallow it.
|
||
For Python modules, the only relevant class to subclass is
|
||
<code class="docutils literal notranslate"><span class="pre">function</span></code> because the others cannot be instantiated anyway.</p>
|
||
</section>
|
||
<section id="replacing-tp-call-meth-pass-function-and-meth-call-unbound">
|
||
<h3><a class="toc-backref" href="#replacing-tp-call-meth-pass-function-and-meth-call-unbound" role="doc-backlink">Replacing tp_call: METH_PASS_FUNCTION and METH_CALL_UNBOUND</a></h3>
|
||
<p>The new flags <code class="docutils literal notranslate"><span class="pre">METH_PASS_FUNCTION</span></code> and <code class="docutils literal notranslate"><span class="pre">METH_CALL_UNBOUND</span></code>
|
||
are meant to support cases where formerly a custom <code class="docutils literal notranslate"><span class="pre">tp_call</span></code> was used.
|
||
It reduces the number of special fast paths in <code class="docutils literal notranslate"><span class="pre">Python/ceval.c</span></code>
|
||
for calling objects:
|
||
instead of treating Python functions, built-in functions and method descriptors
|
||
separately, there would only be a single check.</p>
|
||
<p>The signature of <code class="docutils literal notranslate"><span class="pre">tp_call</span></code> is essentially the signature
|
||
of <code class="docutils literal notranslate"><span class="pre">PyBaseFunctionObject.m_ml.ml_meth</span></code> with flags
|
||
<code class="docutils literal notranslate"><span class="pre">METH_VARARGS</span> <span class="pre">|</span> <span class="pre">METH_KEYWORDS</span> <span class="pre">|</span> <span class="pre">METH_PASS_FUNCTION</span> <span class="pre">|</span> <span class="pre">METH_CALL_UNBOUND</span></code>
|
||
(the only difference is an added <code class="docutils literal notranslate"><span class="pre">self</span></code> argument).
|
||
Therefore, it should be easy to change existing <code class="docutils literal notranslate"><span class="pre">tp_call</span></code> slots
|
||
to use the <code class="docutils literal notranslate"><span class="pre">base_function</span></code> implementation instead.</p>
|
||
<p>It also makes sense to use <code class="docutils literal notranslate"><span class="pre">METH_PASS_FUNCTION</span></code> without <code class="docutils literal notranslate"><span class="pre">METH_CALL_UNBOUND</span></code>
|
||
in cases where the C function simply needs access to additional metadata
|
||
from the function, such as the <code class="docutils literal notranslate"><span class="pre">__parent__</span></code>.
|
||
This is for example needed to support <a class="pep reference internal" href="../pep-0573/" title="PEP 573 – Module State Access from C Extension Methods">PEP 573</a>.
|
||
Converting existing methods to use <code class="docutils literal notranslate"><span class="pre">METH_PASS_FUNCTION</span></code> is trivial:
|
||
it only requires adding an extra argument to the C function.</p>
|
||
</section>
|
||
</section>
|
||
<section id="backwards-compatibility">
|
||
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards compatibility</a></h2>
|
||
<p>While designing this PEP, great care was taken to not break
|
||
backwards compatibility too much.
|
||
Most of the potentially incompatible changes
|
||
are changes to CPython implementation details
|
||
which are different anyway in other Python interpreters.
|
||
In particular, Python code which correctly runs on PyPy
|
||
will very likely continue to work with this PEP.</p>
|
||
<p>The standard classes and functions like
|
||
<code class="docutils literal notranslate"><span class="pre">staticmethod</span></code>, <code class="docutils literal notranslate"><span class="pre">functools.partial</span></code> or <code class="docutils literal notranslate"><span class="pre">operator.methodcaller</span></code>
|
||
do not need to change at all.</p>
|
||
<section id="changes-to-types-and-inspect">
|
||
<h3><a class="toc-backref" href="#changes-to-types-and-inspect" role="doc-backlink">Changes to types and inspect</a></h3>
|
||
<p>The proposed changes to <code class="docutils literal notranslate"><span class="pre">types</span></code> and <code class="docutils literal notranslate"><span class="pre">inspect</span></code>
|
||
are meant to minimize changes in behaviour.
|
||
However, it is unavoidable that some things change
|
||
and this can cause code which uses <code class="docutils literal notranslate"><span class="pre">types</span></code> or <code class="docutils literal notranslate"><span class="pre">inspect</span></code> to break.
|
||
In the Python standard library for example,
|
||
changes are needed in the <code class="docutils literal notranslate"><span class="pre">doctest</span></code> module because of this.</p>
|
||
<p>Also, tools which take various kinds of functions as input will need to deal
|
||
with the new function hierarchy and the possibility of custom
|
||
function classes.</p>
|
||
</section>
|
||
<section id="python-functions">
|
||
<h3><a class="toc-backref" href="#python-functions" role="doc-backlink">Python functions</a></h3>
|
||
<p>For Python functions, essentially nothing changes.
|
||
The attributes that existed before still exist and Python functions
|
||
can be initialized, called and turned into methods as before.</p>
|
||
<p>The name <code class="docutils literal notranslate"><span class="pre">function</span></code> is kept for backwards compatibility.
|
||
While it might make sense to change the name to something more
|
||
specific like <code class="docutils literal notranslate"><span class="pre">python_function</span></code>,
|
||
that would require a lot of annoying changes in documentation and testsuites.</p>
|
||
</section>
|
||
<section id="id7">
|
||
<h3><a class="toc-backref" href="#id7" role="doc-backlink">Built-in functions of a module</a></h3>
|
||
<p>Also for built-in functions, nothing changes.
|
||
We keep the old behaviour that such functions do not bind as methods.
|
||
This is a consequence of the fact that <code class="docutils literal notranslate"><span class="pre">__self__</span></code> is set to the module.</p>
|
||
</section>
|
||
<section id="built-in-bound-and-unbound-methods">
|
||
<h3><a class="toc-backref" href="#built-in-bound-and-unbound-methods" role="doc-backlink">Built-in bound and unbound methods</a></h3>
|
||
<p>The types of built-in bound and unbound methods will change.
|
||
However, this does not affect calling such methods
|
||
because the protocol in <code class="docutils literal notranslate"><span class="pre">base_function.__call__</span></code>
|
||
(in particular the handling of <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code> and self slicing)
|
||
was specifically designed to be backwards compatible.
|
||
All attributes which existed before (like <code class="docutils literal notranslate"><span class="pre">__objclass__</span></code> and <code class="docutils literal notranslate"><span class="pre">__self__</span></code>)
|
||
still exist.</p>
|
||
</section>
|
||
<section id="new-attributes">
|
||
<h3><a class="toc-backref" href="#new-attributes" role="doc-backlink">New attributes</a></h3>
|
||
<p>Some objects get new special double-underscore attributes.
|
||
For example, the new attribute <code class="docutils literal notranslate"><span class="pre">__parent__</span></code> appears on
|
||
all built-in functions and all methods get a <code class="docutils literal notranslate"><span class="pre">__func__</span></code> attribute.
|
||
The fact that <code class="docutils literal notranslate"><span class="pre">__self__</span></code> is now a special read-only attribute
|
||
for Python functions caused trouble in <a class="footnote-reference brackets" href="#bpo33265" id="id8">[4]</a>.
|
||
Generally, we expect that not much will break though.</p>
|
||
</section>
|
||
<section id="method-descriptor-and-pydescr-newmethod">
|
||
<h3><a class="toc-backref" href="#method-descriptor-and-pydescr-newmethod" role="doc-backlink">method_descriptor and PyDescr_NewMethod</a></h3>
|
||
<p>The class <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code> and the constructor <code class="docutils literal notranslate"><span class="pre">PyDescr_NewMethod</span></code>
|
||
should be deprecated.
|
||
They are no longer used by CPython itself but are still supported.</p>
|
||
</section>
|
||
</section>
|
||
<section id="two-phase-implementation">
|
||
<h2><a class="toc-backref" href="#two-phase-implementation" role="doc-backlink">Two-phase Implementation</a></h2>
|
||
<p><strong>TODO</strong>: this section is optional.
|
||
If this PEP is accepted, it should
|
||
be decided whether to apply this two-phase implementation or not.</p>
|
||
<p>As mentioned above, the <a class="reference internal" href="#changes-to-types-and-inspect">changes to types and inspect</a> can break some
|
||
existing code.
|
||
In order to further minimize breakage, this PEP could be implemented
|
||
in two phases.</p>
|
||
<section id="phase-one-keep-existing-classes-but-add-base-classes">
|
||
<h3><a class="toc-backref" href="#phase-one-keep-existing-classes-but-add-base-classes" role="doc-backlink">Phase one: keep existing classes but add base classes</a></h3>
|
||
<p>Initially, implement the <code class="docutils literal notranslate"><span class="pre">base_function</span></code> class
|
||
and use it as common base class but otherwise keep the existing classes
|
||
(but not their implementation).</p>
|
||
<p>In this proposal, the class hierarchy would become:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="nb">object</span>
|
||
<span class="o">|</span>
|
||
<span class="o">|</span>
|
||
<span class="n">base_function</span>
|
||
<span class="o">/</span> <span class="o">|</span> \
|
||
<span class="o">/</span> <span class="o">|</span> \
|
||
<span class="o">/</span> <span class="o">|</span> \
|
||
<span class="n">cfunction</span> <span class="o">|</span> <span class="n">defined_function</span>
|
||
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> \
|
||
<span class="o">|</span> <span class="o">|</span> <span class="n">bound_method</span> \
|
||
<span class="o">|</span> <span class="o">|</span> \
|
||
<span class="o">|</span> <span class="n">method_descriptor</span> <span class="n">function</span>
|
||
<span class="o">|</span>
|
||
<span class="n">builtin_function_or_method</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The leaf classes <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">bound_method</span></code> and <code class="docutils literal notranslate"><span class="pre">function</span></code> correspond to the existing classes
|
||
(with <code class="docutils literal notranslate"><span class="pre">method</span></code> renamed to <code class="docutils literal notranslate"><span class="pre">bound_method</span></code>).</p>
|
||
<p>Automatically created functions created in modules become instances
|
||
of <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code>.
|
||
Unbound methods of extension types become instances of <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code>.</p>
|
||
<p>The class <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code> is a copy of <code class="docutils literal notranslate"><span class="pre">cfunction</span></code> except
|
||
that <code class="docutils literal notranslate"><span class="pre">__get__</span></code> returns a <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> instead of a
|
||
<code class="docutils literal notranslate"><span class="pre">bound_method</span></code>.</p>
|
||
<p>The class <code class="docutils literal notranslate"><span class="pre">builtin_function_or_method</span></code> has the same C structure as a
|
||
<code class="docutils literal notranslate"><span class="pre">bound_method</span></code>, but it inherits from <code class="docutils literal notranslate"><span class="pre">cfunction</span></code>.
|
||
The <code class="docutils literal notranslate"><span class="pre">__func__</span></code> attribute is not mandatory:
|
||
it is only defined when binding a <code class="docutils literal notranslate"><span class="pre">method_descriptor</span></code>.</p>
|
||
<p>We keep the implementation of the <code class="docutils literal notranslate"><span class="pre">inspect</span></code> functions as they are.
|
||
Because of this and because the existing classes are kept,
|
||
backwards compatibility is ensured for code doing type checks.</p>
|
||
<p>Since showing an actual <code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code> would affect a lot
|
||
of correctly-functioning code,
|
||
any deprecations would only appear in the documentation.
|
||
Another reason is that it is hard to show warnings for calling <code class="docutils literal notranslate"><span class="pre">isinstance(x,</span> <span class="pre">t)</span></code>
|
||
(but it could be done using <code class="docutils literal notranslate"><span class="pre">__instancecheck__</span></code> hacking)
|
||
and impossible for <code class="docutils literal notranslate"><span class="pre">type(x)</span> <span class="pre">is</span> <span class="pre">t</span></code>.</p>
|
||
</section>
|
||
<section id="phase-two">
|
||
<h3><a class="toc-backref" href="#phase-two" role="doc-backlink">Phase two</a></h3>
|
||
<p>Phase two is what is actually described in the rest of this PEP.
|
||
In terms of implementation,
|
||
it would be a relatively small change compared to phase one.</p>
|
||
</section>
|
||
</section>
|
||
<section id="reference-implementation">
|
||
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
|
||
<p>Most of this PEP has been implemented for CPython at
|
||
<a class="reference external" href="https://github.com/jdemeyer/cpython/tree/pep575">https://github.com/jdemeyer/cpython/tree/pep575</a></p>
|
||
<p>There are four steps, corresponding to the commits on that branch.
|
||
After each step, CPython is in a mostly working state.</p>
|
||
<ol class="arabic simple">
|
||
<li>Add the <code class="docutils literal notranslate"><span class="pre">base_function</span></code> class and make it a subclass for <code class="docutils literal notranslate"><span class="pre">cfunction</span></code>.
|
||
This is by far the biggest step as the complete <code class="docutils literal notranslate"><span class="pre">__call__</span></code> protocol
|
||
is implemented in this step.</li>
|
||
<li>Rename <code class="docutils literal notranslate"><span class="pre">method</span></code> to <code class="docutils literal notranslate"><span class="pre">bound_method</span></code> and make it a subclass of <code class="docutils literal notranslate"><span class="pre">base_function</span></code>.
|
||
Change unbound methods of extension types to be instances of <code class="docutils literal notranslate"><span class="pre">cfunction</span></code>
|
||
such that bound methods of extension types are also instances of <code class="docutils literal notranslate"><span class="pre">bound_method</span></code>.</li>
|
||
<li>Implement <code class="docutils literal notranslate"><span class="pre">defined_function</span></code> and <code class="docutils literal notranslate"><span class="pre">function</span></code>.</li>
|
||
<li>Changes to other parts of Python, such as the standard library and testsuite.</li>
|
||
</ol>
|
||
</section>
|
||
<section id="appendix-current-situation">
|
||
<h2><a class="toc-backref" href="#appendix-current-situation" role="doc-backlink">Appendix: current situation</a></h2>
|
||
<p><strong>NOTE</strong>:
|
||
This section is more useful during the draft period of the PEP,
|
||
so feel free to remove this once the PEP has been accepted.</p>
|
||
<p>For reference, we describe in detail the relevant existing classes in CPython 3.7.</p>
|
||
<p>Each of the classes involved is an “orphan” class
|
||
(no non-trivial subclasses nor superclasses).</p>
|
||
<section id="builtin-function-or-method-built-in-functions-and-bound-methods">
|
||
<h3><a class="toc-backref" href="#builtin-function-or-method-built-in-functions-and-bound-methods" role="doc-backlink">builtin_function_or_method: built-in functions and bound methods</a></h3>
|
||
<p>These are of type <a class="reference external" href="https://github.com/python/cpython/blob/2cb4661707818cfd92556e7fdf9068a993577002/Objects/methodobject.c#L271">PyCFunction_Type</a>
|
||
with structure <a class="reference external" href="https://github.com/python/cpython/blob/2cb4661707818cfd92556e7fdf9068a993577002/Include/methodobject.h#L102">PyCFunctionObject</a>:</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">PyObject_HEAD</span>
|
||
<span class="n">PyMethodDef</span> <span class="o">*</span><span class="n">m_ml</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Description</span> <span class="n">of</span> <span class="n">the</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">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">func</span><span class="p">,</span> <span class="n">can</span> <span class="n">be</span> <span class="n">NULL</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="n">The</span> <span class="vm">__module__</span> <span class="n">attribute</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">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>
|
||
|
||
<span class="n">struct</span> <span class="n">PyMethodDef</span> <span class="p">{</span>
|
||
<span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">ml_name</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="n">name</span> <span class="n">of</span> <span class="n">the</span> <span class="n">built</span><span class="o">-</span><span class="ow">in</span> <span class="n">function</span><span class="o">/</span><span class="n">method</span> <span class="o">*/</span>
|
||
<span class="n">PyCFunction</span> <span class="n">ml_meth</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="n">C</span> <span class="n">function</span> <span class="n">that</span> <span class="n">implements</span> <span class="n">it</span> <span class="o">*/</span>
|
||
<span class="nb">int</span> <span class="n">ml_flags</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Combination</span> <span class="n">of</span> <span class="n">METH_xxx</span> <span class="n">flags</span><span class="p">,</span> <span class="n">which</span> <span class="n">mostly</span>
|
||
<span class="n">describe</span> <span class="n">the</span> <span class="n">args</span> <span class="n">expected</span> <span class="n">by</span> <span class="n">the</span> <span class="n">C</span> <span class="n">func</span> <span class="o">*/</span>
|
||
<span class="n">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">ml_doc</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="vm">__doc__</span> <span class="n">attribute</span><span class="p">,</span> <span class="ow">or</span> <span class="n">NULL</span> <span class="o">*/</span>
|
||
<span class="p">};</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>where <code class="docutils literal notranslate"><span class="pre">PyCFunction</span></code> is a C function pointer (there are various forms of this, the most basic
|
||
takes two arguments for <code class="docutils literal notranslate"><span class="pre">self</span></code> and <code class="docutils literal notranslate"><span class="pre">*args</span></code>).</p>
|
||
<p>This class is used both for functions and bound methods:
|
||
for a method, the <code class="docutils literal notranslate"><span class="pre">m_self</span></code> slot points to the object:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">dict</span><span class="p">(</span><span class="n">foo</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span><span class="o">.</span><span class="n">get</span>
|
||
<span class="go"><built-in method get of dict object at 0x...></span>
|
||
<span class="gp">>>> </span><span class="nb">dict</span><span class="p">(</span><span class="n">foo</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="o">.</span><span class="vm">__self__</span>
|
||
<span class="go">{'foo': 42}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>In some cases, a function is considered a “method” of the module defining it:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">os</span>
|
||
<span class="gp">>>> </span><span class="n">os</span><span class="o">.</span><span class="n">kill</span>
|
||
<span class="go"><built-in function kill></span>
|
||
<span class="gp">>>> </span><span class="n">os</span><span class="o">.</span><span class="n">kill</span><span class="o">.</span><span class="vm">__self__</span>
|
||
<span class="go"><module 'posix' (built-in)></span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="method-descriptor-built-in-unbound-methods">
|
||
<h3><a class="toc-backref" href="#method-descriptor-built-in-unbound-methods" role="doc-backlink">method_descriptor: built-in unbound methods</a></h3>
|
||
<p>These are of type <a class="reference external" href="https://github.com/python/cpython/blob/2cb4661707818cfd92556e7fdf9068a993577002/Objects/descrobject.c#L538">PyMethodDescr_Type</a>
|
||
with structure <a class="reference external" href="https://github.com/python/cpython/blob/2cb4661707818cfd92556e7fdf9068a993577002/Include/descrobject.h#L53">PyMethodDescrObject</a>:</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">PyDescrObject</span> <span class="n">d_common</span><span class="p">;</span>
|
||
<span class="n">PyMethodDef</span> <span class="o">*</span><span class="n">d_method</span><span class="p">;</span>
|
||
<span class="p">}</span> <span class="n">PyMethodDescrObject</span><span class="p">;</span>
|
||
|
||
<span class="n">typedef</span> <span class="n">struct</span> <span class="p">{</span>
|
||
<span class="n">PyObject_HEAD</span>
|
||
<span class="n">PyTypeObject</span> <span class="o">*</span><span class="n">d_type</span><span class="p">;</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">d_name</span><span class="p">;</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">d_qualname</span><span class="p">;</span>
|
||
<span class="p">}</span> <span class="n">PyDescrObject</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="function-python-functions">
|
||
<h3><a class="toc-backref" href="#function-python-functions" role="doc-backlink">function: Python functions</a></h3>
|
||
<p>These are of type <a class="reference external" href="https://github.com/python/cpython/blob/2cb4661707818cfd92556e7fdf9068a993577002/Objects/funcobject.c#L592">PyFunction_Type</a>
|
||
with structure <a class="reference external" href="https://github.com/python/cpython/blob/2cb4661707818cfd92556e7fdf9068a993577002/Include/funcobject.h#L21">PyFunctionObject</a>:</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">PyObject_HEAD</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_code</span><span class="p">;</span> <span class="o">/*</span> <span class="n">A</span> <span class="n">code</span> <span class="nb">object</span><span class="p">,</span> <span class="n">the</span> <span class="vm">__code__</span> <span class="n">attribute</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_globals</span><span class="p">;</span> <span class="o">/*</span> <span class="n">A</span> <span class="n">dictionary</span> <span class="p">(</span><span class="n">other</span> <span class="n">mappings</span> <span class="n">won</span><span class="s1">'t do) */</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_defaults</span><span class="p">;</span> <span class="o">/*</span> <span class="n">NULL</span> <span class="ow">or</span> <span class="n">a</span> <span class="nb">tuple</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_kwdefaults</span><span class="p">;</span> <span class="o">/*</span> <span class="n">NULL</span> <span class="ow">or</span> <span class="n">a</span> <span class="nb">dict</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_closure</span><span class="p">;</span> <span class="o">/*</span> <span class="n">NULL</span> <span class="ow">or</span> <span class="n">a</span> <span class="nb">tuple</span> <span class="n">of</span> <span class="n">cell</span> <span class="n">objects</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_doc</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="vm">__doc__</span> <span class="n">attribute</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">PyObject</span> <span class="o">*</span><span class="n">func_name</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="vm">__name__</span> <span class="n">attribute</span><span class="p">,</span> <span class="n">a</span> <span class="n">string</span> <span class="nb">object</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_dict</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="vm">__dict__</span> <span class="n">attribute</span><span class="p">,</span> <span class="n">a</span> <span class="nb">dict</span> <span class="ow">or</span> <span class="n">NULL</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_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="n">PyObject</span> <span class="o">*</span><span class="n">func_module</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="vm">__module__</span> <span class="n">attribute</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">PyObject</span> <span class="o">*</span><span class="n">func_annotations</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Annotations</span><span class="p">,</span> <span class="n">a</span> <span class="nb">dict</span> <span class="ow">or</span> <span class="n">NULL</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">func_qualname</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="n">qualified</span> <span class="n">name</span> <span class="o">*/</span>
|
||
|
||
<span class="o">/*</span> <span class="n">Invariant</span><span class="p">:</span>
|
||
<span class="o">*</span> <span class="n">func_closure</span> <span class="n">contains</span> <span class="n">the</span> <span class="n">bindings</span> <span class="k">for</span> <span class="n">func_code</span><span class="o">-></span><span class="n">co_freevars</span><span class="p">,</span> <span class="n">so</span>
|
||
<span class="o">*</span> <span class="n">PyTuple_Size</span><span class="p">(</span><span class="n">func_closure</span><span class="p">)</span> <span class="o">==</span> <span class="n">PyCode_GetNumFree</span><span class="p">(</span><span class="n">func_code</span><span class="p">)</span>
|
||
<span class="o">*</span> <span class="p">(</span><span class="n">func_closure</span> <span class="n">may</span> <span class="n">be</span> <span class="n">NULL</span> <span class="k">if</span> <span class="n">PyCode_GetNumFree</span><span class="p">(</span><span class="n">func_code</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span>
|
||
<span class="o">*/</span>
|
||
<span class="p">}</span> <span class="n">PyFunctionObject</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>In Python 3, there is no “unbound method” class:
|
||
an unbound method is just a plain function.</p>
|
||
</section>
|
||
<section id="method-python-bound-methods">
|
||
<h3><a class="toc-backref" href="#method-python-bound-methods" role="doc-backlink">method: Python bound methods</a></h3>
|
||
<p>These are of type <a class="reference external" href="https://github.com/python/cpython/blob/2cb4661707818cfd92556e7fdf9068a993577002/Objects/classobject.c#L329">PyMethod_Type</a>
|
||
with structure <a class="reference external" href="https://github.com/python/cpython/blob/2cb4661707818cfd92556e7fdf9068a993577002/Include/classobject.h#L12">PyMethodObject</a>:</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">PyObject_HEAD</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">im_func</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="nb">callable</span> <span class="nb">object</span> <span class="n">implementing</span> <span class="n">the</span> <span class="n">method</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">im_self</span><span class="p">;</span> <span class="o">/*</span> <span class="n">The</span> <span class="n">instance</span> <span class="n">it</span> <span class="ow">is</span> <span class="n">bound</span> <span class="n">to</span> <span class="o">*/</span>
|
||
<span class="n">PyObject</span> <span class="o">*</span><span class="n">im_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">PyMethodObject</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</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="cython" role="doc-footnote">
|
||
<dt class="label" id="cython">[1]<em> (<a href='#id1'>1</a>, <a href='#id3'>2</a>) </em></dt>
|
||
<dd>Cython (<a class="reference external" href="http://cython.org/">http://cython.org/</a>)</aside>
|
||
<aside class="footnote brackets" id="bpo30071" role="doc-footnote">
|
||
<dt class="label" id="bpo30071">[<a href="#id2">2</a>]</dt>
|
||
<dd>Python bug 30071, Duck-typing inspect.isfunction() (<a class="reference external" href="https://bugs.python.org/issue30071">https://bugs.python.org/issue30071</a>)</aside>
|
||
<aside class="footnote brackets" id="bpo33261" role="doc-footnote">
|
||
<dt class="label" id="bpo33261">[<a href="#id6">3</a>]</dt>
|
||
<dd>Python bug 33261, inspect.isgeneratorfunction fails on hand-created methods
|
||
(<a class="reference external" href="https://bugs.python.org/issue33261">https://bugs.python.org/issue33261</a> and <a class="reference external" href="https://github.com/python/cpython/pull/6448">https://github.com/python/cpython/pull/6448</a>)</aside>
|
||
<aside class="footnote brackets" id="bpo33265" role="doc-footnote">
|
||
<dt class="label" id="bpo33265">[<a href="#id8">4</a>]</dt>
|
||
<dd>Python bug 33265, contextlib.ExitStack abuses __self__
|
||
(<a class="reference external" href="https://bugs.python.org/issue33265">https://bugs.python.org/issue33265</a> and <a class="reference external" href="https://github.com/python/cpython/pull/6456">https://github.com/python/cpython/pull/6456</a>)</aside>
|
||
<aside class="footnote brackets" id="methoddoc" role="doc-footnote">
|
||
<dt class="label" id="methoddoc">[<a href="#id4">5</a>]</dt>
|
||
<dd>PyMethodDef documentation (<a class="reference external" href="https://docs.python.org/3.7/c-api/structures.html#c.PyMethodDef">https://docs.python.org/3.7/c-api/structures.html#c.PyMethodDef</a>)</aside>
|
||
<aside class="footnote brackets" id="proposal" role="doc-footnote">
|
||
<dt class="label" id="proposal">[<a href="#id5">6</a>]</dt>
|
||
<dd>PEP proposal: unifying function/method classes (<a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2018-March/049398.html">https://mail.python.org/pipermail/python-ideas/2018-March/049398.html</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-0575.rst">https://github.com/python/peps/blob/main/peps/pep-0575.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0575.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="#withdrawal-notice">Withdrawal 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="#new-classes">New classes</a><ul>
|
||
<li><a class="reference internal" href="#base-function">base_function</a></li>
|
||
<li><a class="reference internal" href="#cfunction">cfunction</a></li>
|
||
<li><a class="reference internal" href="#defined-function">defined_function</a></li>
|
||
<li><a class="reference internal" href="#function">function</a></li>
|
||
<li><a class="reference internal" href="#bound-method">bound_method</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#calling-base-function-instances">Calling base_function instances</a><ul>
|
||
<li><a class="reference internal" href="#checking-objclass">Checking __objclass__</a></li>
|
||
<li><a class="reference internal" href="#flags">Flags</a></li>
|
||
<li><a class="reference internal" href="#self-slicing">Self slicing</a></li>
|
||
<li><a class="reference internal" href="#meth-pass-function">METH_PASS_FUNCTION</a></li>
|
||
<li><a class="reference internal" href="#meth-fastcall">METH_FASTCALL</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#automatic-creation-of-built-in-functions">Automatic creation of built-in functions</a><ul>
|
||
<li><a class="reference internal" href="#unbound-methods-of-extension-types">Unbound methods of extension types</a></li>
|
||
<li><a class="reference internal" href="#built-in-functions-of-a-module">Built-in functions of a module</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#further-changes">Further changes</a><ul>
|
||
<li><a class="reference internal" href="#new-type-flag">New type flag</a></li>
|
||
<li><a class="reference internal" href="#c-api-functions">C API functions</a></li>
|
||
<li><a class="reference internal" href="#changes-to-the-types-module">Changes to the types module</a></li>
|
||
<li><a class="reference internal" href="#changes-to-the-inspect-module">Changes to the inspect module</a></li>
|
||
<li><a class="reference internal" href="#profiling">Profiling</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#non-cpython-implementations">Non-CPython implementations</a></li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
|
||
<li><a class="reference internal" href="#why-not-simply-change-existing-classes">Why not simply change existing classes?</a></li>
|
||
<li><a class="reference internal" href="#why-text-signature-is-not-a-solution">Why __text_signature__ is not a solution</a></li>
|
||
<li><a class="reference internal" href="#defined-function-versus-function">defined_function versus function</a></li>
|
||
<li><a class="reference internal" href="#scope-of-this-pep-which-classes-are-involved">Scope of this PEP: which classes are involved?</a></li>
|
||
<li><a class="reference internal" href="#not-treating-meth-static-and-meth-class">Not treating METH_STATIC and METH_CLASS</a></li>
|
||
<li><a class="reference internal" href="#self-in-base-function">__self__ in base_function</a></li>
|
||
<li><a class="reference internal" href="#two-implementations-of-doc">Two implementations of __doc__</a></li>
|
||
<li><a class="reference internal" href="#subclassing">Subclassing</a></li>
|
||
<li><a class="reference internal" href="#replacing-tp-call-meth-pass-function-and-meth-call-unbound">Replacing tp_call: METH_PASS_FUNCTION and METH_CALL_UNBOUND</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards compatibility</a><ul>
|
||
<li><a class="reference internal" href="#changes-to-types-and-inspect">Changes to types and inspect</a></li>
|
||
<li><a class="reference internal" href="#python-functions">Python functions</a></li>
|
||
<li><a class="reference internal" href="#id7">Built-in functions of a module</a></li>
|
||
<li><a class="reference internal" href="#built-in-bound-and-unbound-methods">Built-in bound and unbound methods</a></li>
|
||
<li><a class="reference internal" href="#new-attributes">New attributes</a></li>
|
||
<li><a class="reference internal" href="#method-descriptor-and-pydescr-newmethod">method_descriptor and PyDescr_NewMethod</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#two-phase-implementation">Two-phase Implementation</a><ul>
|
||
<li><a class="reference internal" href="#phase-one-keep-existing-classes-but-add-base-classes">Phase one: keep existing classes but add base classes</a></li>
|
||
<li><a class="reference internal" href="#phase-two">Phase two</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
|
||
<li><a class="reference internal" href="#appendix-current-situation">Appendix: current situation</a><ul>
|
||
<li><a class="reference internal" href="#builtin-function-or-method-built-in-functions-and-bound-methods">builtin_function_or_method: built-in functions and bound methods</a></li>
|
||
<li><a class="reference internal" href="#method-descriptor-built-in-unbound-methods">method_descriptor: built-in unbound methods</a></li>
|
||
<li><a class="reference internal" href="#function-python-functions">function: Python functions</a></li>
|
||
<li><a class="reference internal" href="#method-python-bound-methods">method: Python bound methods</a></li>
|
||
</ul>
|
||
</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-0575.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> |