PEP 580: minor update (#882)
This commit is contained in:
parent
0ace9bf0f0
commit
33459e7b49
108
pep-0580.rst
108
pep-0580.rst
|
@ -30,17 +30,27 @@ it does not affect the Python language or standard library.
|
||||||
Motivation
|
Motivation
|
||||||
==========
|
==========
|
||||||
|
|
||||||
Currently, the Python bytecode interpreter has various optimizations
|
The standard function/method classes ``builtin_function_or_method``
|
||||||
for calling instances of ``builtin_function_or_method``,
|
and ``method_descriptor`` allow very efficiently calling C code.
|
||||||
``method_descriptor``, ``method`` and ``function``.
|
However, they are not subclassable, making them unsuitable for many applications:
|
||||||
However, none of these classes is subclassable.
|
for example, they offer limited introspection support
|
||||||
Therefore, these optimizations are not available to
|
(signatures only using ``__text_signature__``, no arbitrary ``__qualname__``,
|
||||||
user-defined extension types.
|
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
|
This PEP also allows to simplify existing code:
|
||||||
for ``builtin_function_or_method`` and ``method_descriptor``
|
checks for ``builtin_function_or_method`` and ``method_descriptor``
|
||||||
could be replaced by simply checking for and using the C call protocol.
|
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
|
We also design the C call protocol such that it can easily
|
||||||
be extended with new features in the future.
|
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.
|
For more background and motivation, see PEP 579.
|
||||||
|
|
||||||
|
|
||||||
Basic idea
|
Overview
|
||||||
==========
|
========
|
||||||
|
|
||||||
Currently, CPython has multiple optimizations for fast calling
|
Currently, CPython has multiple optimizations for fast calling
|
||||||
for a few specific function classes.
|
for a few specific function classes.
|
||||||
Calling instances of these classes using the ``tp_call`` slot is slower
|
A good example is the implementation of the opcode ``CALL_FUNCTION``,
|
||||||
than using the optimizations.
|
which has the following structure
|
||||||
The basic idea of this PEP is to allow user-defined extension types
|
(`see the actual code <https://github.com/python/cpython/blob/7a2368063f25746d4008a74aca0dc0b82f86ff7b/Python/ceval.c#L4592>`_)::
|
||||||
(not Python classes) to use these optimizations also,
|
|
||||||
both as caller and as callee.
|
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
|
The existing class ``builtin_function_or_method`` and a few others
|
||||||
use a ``PyMethodDef`` structure for describing the underlying C function and its signature.
|
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
|
The new protocol for efficiently calling objects using these new structures
|
||||||
is called the "C call protocol".
|
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
|
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
|
For methods of extension types, ``cc_parent`` points to the class
|
||||||
that defines the method (which may be a superclass of ``type(self)``).
|
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.
|
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
|
In the future, this can be used to access the module state via
|
||||||
the defining class. See the rationale of PEP 573 for details.)
|
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
|
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::
|
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__``
|
The C call protocol requires that the function has a ``__name__``
|
||||||
attribute which is of type ``str`` (not a subclass).
|
attribute which is of type ``str`` (not a subclass).
|
||||||
|
|
||||||
Furthermore, this must be idempotent in the sense
|
Furthermore, the object returned by ``__name__`` must be stored somewhere;
|
||||||
that getting the ``__name__`` attribute twice in a row must return
|
it cannot be a temporary object.
|
||||||
exactly the same Python object.
|
|
||||||
This implies that it cannot be a temporary object, it must be stored somewhere.
|
|
||||||
This is required because ``PyEval_GetFuncName``
|
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
|
Generic API functions
|
||||||
---------------------
|
---------------------
|
||||||
|
@ -622,7 +657,7 @@ Another minor advantage is that we could
|
||||||
make the error messages for a wrong call signature
|
make the error messages for a wrong call signature
|
||||||
more uniform between Python methods and built-in methods.
|
more uniform between Python methods and built-in methods.
|
||||||
In the following example, Python is undecided whether
|
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):
|
>>> class List(list):
|
||||||
... def myappend(self, item):
|
... 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.
|
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
|
Reference implementation
|
||||||
========================
|
========================
|
||||||
|
|
||||||
|
@ -677,6 +733,8 @@ References
|
||||||
.. [#bpo29259] Add tp_fastcall to PyTypeObject: support FASTCALL calling convention for all callable objects,
|
.. [#bpo29259] Add tp_fastcall to PyTypeObject: support FASTCALL calling convention for all callable objects,
|
||||||
https://bugs.python.org/issue29259
|
https://bugs.python.org/issue29259
|
||||||
|
|
||||||
|
.. [#badcapi] Bad C API,
|
||||||
|
https://pythoncapi.readthedocs.io/bad_api.html#bad-c-api
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
=========
|
=========
|
||||||
|
|
Loading…
Reference in New Issue