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 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
========= =========