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
|
||||
==========
|
||||
|
||||
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
|
||||
=========
|
||||
|
|
Loading…
Reference in New Issue