PEP 580: minor update (#882)

This commit is contained in:
jdemeyer 2019-01-25 10:17:12 +01:00 committed by Inada Naoki
parent 0ace9bf0f0
commit 33459e7b49
1 changed files with 83 additions and 25 deletions

View File

@ -30,17 +30,27 @@ it does not affect the Python language or standard library.
Motivation
==========
Currently, the Python bytecode interpreter has various optimizations
for calling instances of ``builtin_function_or_method``,
``method_descriptor``, ``method`` and ``function``.
However, none of these classes is subclassable.
Therefore, these optimizations are not available to
user-defined extension types.
The standard function/method classes ``builtin_function_or_method``
and ``method_descriptor`` allow very efficiently calling C code.
However, they are not subclassable, making them unsuitable for many applications:
for example, they offer limited introspection support
(signatures only using ``__text_signature__``, no arbitrary ``__qualname__``,
no ``inspect.getfile()``).
It's also not possible to store additional data to implement something like
``functools.partial`` or ``functools.lru_cache``.
So, there are many reasons why users would want to implement custom
function/method classes (in a duck-typing sense) in C.
Unfortunately, such custom classes are necessarily slower than
the standard CPython function classes:
the bytecode interpreter has various optimizations
which are specific to instances of
``builtin_function_or_method``, ``method_descriptor``, ``method`` and ``function``.
If this PEP is implemented, then the checks
for ``builtin_function_or_method`` and ``method_descriptor``
This PEP also allows to simplify existing code:
checks for ``builtin_function_or_method`` and ``method_descriptor``
could be replaced by simply checking for and using the C call protocol.
This simplifies existing code.
Future PEPs may implement the C call protocol for more classes,
enabling even further simplifications.
We also design the C call protocol such that it can easily
be extended with new features in the future.
@ -48,16 +58,37 @@ be extended with new features in the future.
For more background and motivation, see PEP 579.
Basic idea
==========
Overview
========
Currently, CPython has multiple optimizations for fast calling
for a few specific function classes.
Calling instances of these classes using the ``tp_call`` slot is slower
than using the optimizations.
The basic idea of this PEP is to allow user-defined extension types
(not Python classes) to use these optimizations also,
both as caller and as callee.
A good example is the implementation of the opcode ``CALL_FUNCTION``,
which has the following structure
(`see the actual code <https://github.com/python/cpython/blob/7a2368063f25746d4008a74aca0dc0b82f86ff7b/Python/ceval.c#L4592>`_)::
if (PyCFunction_Check(func)) {
return _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames);
}
else if (Py_TYPE(func) == &PyMethodDescr_Type) {
return _PyMethodDescr_FastCallKeywords(func, stack, nargs, kwnames);
}
else {
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
/* ... */
}
if (PyFunction_Check(func)) {
return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
}
else {
return _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
}
}
Calling instances of these special-cased classes
using the ``tp_call`` slot is slower than using the optimizations.
The basic idea of this PEP is to enable such optimizations
for user C code, both as caller and as callee.
The existing class ``builtin_function_or_method`` and a few others
use a ``PyMethodDef`` structure for describing the underlying C function and its signature.
@ -82,6 +113,11 @@ These two fields together are referred to as a ``PyCCallRoot`` structure.
The new protocol for efficiently calling objects using these new structures
is called the "C call protocol".
**NOTE**: In this PEP, the phrases "unbound method" and "bound method"
refer to generic behavior, not to specific classes.
For example, an unbound method gets turned into a bound method
after applying ``__get__``.
New data structures
===================
@ -130,9 +166,9 @@ It is only used by the C call protocol if the
For methods of extension types, ``cc_parent`` points to the class
that defines the method (which may be a superclass of ``type(self)``).
This is currently is non-trivial to retreive from a method's code.
(In the future, this can be used to access the module state via
the defining class. See the rationale of PEP 573 for details.)
This is currently non-trivial to retrieve from a method's code.
In the future, this can be used to access the module state via
the defining class. See the rationale of PEP 573 for details.
When the flag ``CCALL_OBJCLASS`` is set (as it will be for methods of
extension types), ``cc_parent`` is used for type checks like the following::
@ -335,12 +371,11 @@ The __name__ attribute
The C call protocol requires that the function has a ``__name__``
attribute which is of type ``str`` (not a subclass).
Furthermore, this must be idempotent in the sense
that getting the ``__name__`` attribute twice in a row must return
exactly the same Python object.
This implies that it cannot be a temporary object, it must be stored somewhere.
Furthermore, the object returned by ``__name__`` must be stored somewhere;
it cannot be a temporary object.
This is required because ``PyEval_GetFuncName``
uses a borrowed reference to the ``__name__`` attribute.
uses a borrowed reference to the ``__name__`` attribute
(see also [#badcapi]_).
Generic API functions
---------------------
@ -622,7 +657,7 @@ Another minor advantage is that we could
make the error messages for a wrong call signature
more uniform between Python methods and built-in methods.
In the following example, Python is undecided whether
a method takes 2 or 3 arguments::
a method takes 1 or 2 arguments::
>>> class List(list):
... def myappend(self, item):
@ -661,6 +696,27 @@ See https://mail.python.org/pipermail/python-dev/2018-July/154238.html
for comments on the difference between PEP 576 and PEP 580.
Discussion
==========
Links to threads on the ``python-dev`` mailing list
where this PEP has been discussed:
- https://mail.python.org/pipermail/python-dev/2018-June/153938.html
- https://mail.python.org/pipermail/python-dev/2018-June/153984.html
- https://mail.python.org/pipermail/python-dev/2018-July/154238.html
- https://mail.python.org/pipermail/python-dev/2018-July/154470.html
- https://mail.python.org/pipermail/python-dev/2018-July/154571.html
- https://mail.python.org/pipermail/python-dev/2018-September/155166.html
- https://mail.python.org/pipermail/python-dev/2018-October/155403.html
Reference implementation
========================
@ -677,6 +733,8 @@ References
.. [#bpo29259] Add tp_fastcall to PyTypeObject: support FASTCALL calling convention for all callable objects,
https://bugs.python.org/issue29259
.. [#badcapi] Bad C API,
https://pythoncapi.readthedocs.io/bad_api.html#bad-c-api
Copyright
=========