PEP 580: minor update (#749)
This commit is contained in:
parent
3bdd70578a
commit
84871930a5
84
pep-0580.rst
84
pep-0580.rst
|
@ -23,7 +23,7 @@ this new protocol is used for the existing classes
|
||||||
``builtin_function_or_method`` and ``method_descriptor``.
|
``builtin_function_or_method`` and ``method_descriptor``.
|
||||||
However, in the future, more classes may implement it.
|
However, in the future, more classes may implement it.
|
||||||
|
|
||||||
**NOTE**: This PEP deals only with CPython implementation details,
|
**NOTE**: This PEP deals only with the Python/C API,
|
||||||
it does not affect the Python language or standard library.
|
it does not affect the Python language or standard library.
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,28 +177,34 @@ Its precise signature depends on flags.
|
||||||
Below are the possible values for ``cc_flags & CCALL_SIGNATURE``
|
Below are the possible values for ``cc_flags & CCALL_SIGNATURE``
|
||||||
together with the arguments that the C function takes.
|
together with the arguments that the C function takes.
|
||||||
The return value is always ``PyObject *``.
|
The return value is always ``PyObject *``.
|
||||||
The following are completely analogous to the existing ``PyMethodDef``
|
The following are analogous to the existing ``PyMethodDef``
|
||||||
signature flags:
|
signature flags:
|
||||||
|
|
||||||
- ``CCALL_VARARGS``: ``cc_func(PyObject *self, PyObject *args)``
|
- ``CCALL_VARARGS``:
|
||||||
|
``cc_func(PyObject *self, PyObject *args)``
|
||||||
|
|
||||||
- ``CCALL_VARARGS | CCALL_KEYWORDS``: ``cc_func(PyObject *self, PyObject *args, PyObject *kwds)``
|
- ``CCALL_VARARGS | CCALL_KEYWORDS``:
|
||||||
|
``cc_func(PyObject *self, PyObject *args, PyObject *kwds)``
|
||||||
|
|
||||||
- ``CCALL_FASTCALL``: ``cc_func(PyObject *self, PyObject *const *args, Py_ssize_t nargs)``
|
- ``CCALL_FASTCALL``:
|
||||||
|
``cc_func(PyObject *self, PyObject *const *args, Py_ssize_t nargs)``
|
||||||
|
|
||||||
- ``CCALL_FASTCALL | CCALL_KEYWORDS``: ``cc_func(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)``
|
- ``CCALL_FASTCALL | CCALL_KEYWORDS``:
|
||||||
|
``cc_func(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)``
|
||||||
|
|
||||||
- ``CCALL_NULLARG``: ``cc_func(PyObject *self, PyObject *null)``
|
- ``CCALL_NOARGS``:
|
||||||
(the function takes no arguments but a ``NULL`` is passed to the C function)
|
``cc_func(PyObject *self)``
|
||||||
|
|
||||||
- ``CCALL_O``: ``cc_func(PyObject *self, PyObject *arg)``
|
- ``CCALL_O``:
|
||||||
|
``cc_func(PyObject *self, PyObject *arg)``
|
||||||
|
|
||||||
The flag ``CCALL_FUNCARG`` may be combined with any of these.
|
The flag ``CCALL_FUNCARG`` may be combined with any of these.
|
||||||
If so, the C function takes an additional argument as first argument
|
If so, the C function takes an additional argument as second argument
|
||||||
which is the function object (the ``self`` in ``__call__``).
|
after ``self``.
|
||||||
|
This argument is used to pass the function object (the ``self`` in ``__call__``).
|
||||||
For example, we have the following signature:
|
For example, we have the following signature:
|
||||||
|
|
||||||
- ``CCALL_FUNCARG | CCALL_VARARGS``: ``cc_func(PyObject *func, PyObject *self, PyObject *args)``
|
- ``CCALL_VARARGS | CCALL_FUNCARG``: ``cc_func(PyObject *self, PyObject *func, PyObject *args)``
|
||||||
|
|
||||||
**NOTE**: in the case of bound methods, it is currently unspecified
|
**NOTE**: in the case of bound methods, it is currently unspecified
|
||||||
whether the "function object" in the paragraph above refers
|
whether the "function object" in the paragraph above refers
|
||||||
|
@ -209,6 +215,10 @@ Despite this ambiguity, the implementation of bound methods
|
||||||
guarantees that ``PyCCall_CCALLDEF(func)``
|
guarantees that ``PyCCall_CCALLDEF(func)``
|
||||||
points to the ``PyCCallDef`` of the original function.
|
points to the ``PyCCallDef`` of the original function.
|
||||||
|
|
||||||
|
**NOTE**: ``METH_NOARGS`` takes a second unused argument.
|
||||||
|
This is compatible with ``CCALL_NOARGS | CCALL_FUNCARG``,
|
||||||
|
which also takes two arguments.
|
||||||
|
|
||||||
**NOTE**: unlike the existing ``METH_...`` flags,
|
**NOTE**: unlike the existing ``METH_...`` flags,
|
||||||
the ``CCALL_...`` constants do not necessarily represent single bits.
|
the ``CCALL_...`` constants do not necessarily represent single bits.
|
||||||
So checking ``(cc_flags & CCALL_VARARGS) == 0`` is not a valid way
|
So checking ``(cc_flags & CCALL_VARARGS) == 0`` is not a valid way
|
||||||
|
@ -230,18 +240,18 @@ If not, a ``TypeError`` is raised.
|
||||||
Self slicing
|
Self slicing
|
||||||
------------
|
------------
|
||||||
|
|
||||||
If ``cr_self`` is not NULL or if the flag ``CCALL_SLICE_SELF``
|
If ``cr_self`` is not NULL or if the flag ``CCALL_SELFARG``
|
||||||
is not set in ``cc_flags``, then the argument passed as ``self``
|
is not set in ``cc_flags``, then the argument passed as ``self``
|
||||||
is simply ``cr_self``.
|
is simply ``cr_self``.
|
||||||
|
|
||||||
If ``cr_self`` is NULL and the flag ``CCALL_SLICE_SELF`` is set,
|
If ``cr_self`` is NULL and the flag ``CCALL_SELFARG`` is set,
|
||||||
then the first positional argument is removed from
|
then the first positional argument is removed from
|
||||||
``args`` and instead passed as first argument to the C function.
|
``args`` and instead passed as first argument to the C function.
|
||||||
Effectively, the first positional argument is treated as ``__self__``.
|
Effectively, the first positional argument is treated as ``__self__``.
|
||||||
If there are no positional arguments, ``TypeError`` is raised.
|
If there are no positional arguments, ``TypeError`` is raised.
|
||||||
|
|
||||||
This process is called self slicing and a function is said to have self
|
This process is called self slicing and a function is said to have self
|
||||||
slicing if ``cr_self`` is NULL and ``CCALL_SLICE_SELF`` is set.
|
slicing if ``cr_self`` is NULL and ``CCALL_SELFARG`` is set.
|
||||||
|
|
||||||
Note that a ``METH_NULLARG`` function with self slicing effectively has
|
Note that a ``METH_NULLARG`` function with self slicing effectively has
|
||||||
one argument, namely ``self``.
|
one argument, namely ``self``.
|
||||||
|
@ -294,13 +304,14 @@ Furthermore, this must be idempotent in the sense
|
||||||
that getting the ``__name__`` attribute twice in a row must return
|
that getting the ``__name__`` attribute twice in a row must return
|
||||||
exactly the same Python object.
|
exactly the same Python object.
|
||||||
This implies that it cannot be a temporary object, it must be stored somewhere.
|
This implies that it cannot be a temporary object, it must be stored somewhere.
|
||||||
This is required because ``PyEval_GetFuncName`` and ``PyEval_GetFuncDesc``
|
This is required because ``PyEval_GetFuncName``
|
||||||
use borrowed references to the ``__name__`` attribute.
|
uses a borrowed reference to the ``__name__`` attribute.
|
||||||
|
|
||||||
Generic API functions
|
Generic API functions
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
This section lists the new public API functions dealing with the C call protocol.
|
This section lists the new public API functions or macros
|
||||||
|
dealing with the C call protocol.
|
||||||
|
|
||||||
- ``int PyCCall_Check(PyObject *op)``:
|
- ``int PyCCall_Check(PyObject *op)``:
|
||||||
return true if ``op`` implements the C call protocol.
|
return true if ``op`` implements the C call protocol.
|
||||||
|
@ -346,10 +357,6 @@ Generic getters, meant to be put into the ``tp_getset`` array:
|
||||||
This uses the ``__qualname__`` of ``cc_parent`` if possible.
|
This uses the ``__qualname__`` of ``cc_parent`` if possible.
|
||||||
It also uses the ``__name__`` attribute.
|
It also uses the ``__name__`` attribute.
|
||||||
|
|
||||||
- ``PyObject * PyCCall_GenericGetSelf(PyObject *func, void *closure)``:
|
|
||||||
return ``cr_self``.
|
|
||||||
Raise ``AttributeError`` if ``cr_self`` is NULL.
|
|
||||||
|
|
||||||
Profiling
|
Profiling
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
@ -374,7 +381,7 @@ the implementation becomes very similar, but they remain separate classes
|
||||||
The ``PyCCallDef`` structure is simply stored
|
The ``PyCCallDef`` structure is simply stored
|
||||||
as part of the object structure.
|
as part of the object structure.
|
||||||
Both classes use ``PyCFunctionObject`` as object structure.
|
Both classes use ``PyCFunctionObject`` as object structure.
|
||||||
This is the new layout::
|
This is the new layout for both classes::
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
|
@ -404,7 +411,13 @@ The following function is added (also to the stable ABI [#pep384]_):
|
||||||
|
|
||||||
- ``PyObject * PyCFunction_ClsNew(PyTypeObject *cls, PyMethodDef *ml, PyObject *self, PyObject *module, PyObject *parent)``:
|
- ``PyObject * PyCFunction_ClsNew(PyTypeObject *cls, PyMethodDef *ml, PyObject *self, PyObject *module, PyObject *parent)``:
|
||||||
create a new object with object structure ``PyCFunctionObject`` and class ``cls``.
|
create a new object with object structure ``PyCFunctionObject`` and class ``cls``.
|
||||||
This is called in turn by ``PyCFunction_NewEx`` and ``PyDescr_NewMethod``.
|
Note that the entries of the ``PyMethodDef`` structure are used to construct
|
||||||
|
the new object, but it is no longer stored in the object.
|
||||||
|
The flags for the C call protocol are automatically determined in terms
|
||||||
|
of ``ml->ml_flags``, ``self`` and ``parent``.
|
||||||
|
|
||||||
|
The existing functions ``PyCFunction_New``, ``PyCFunction_NewEx`` and
|
||||||
|
``PyDescr_NewMethod`` are implemented in terms of ``PyCFunction_ClsNew``.
|
||||||
|
|
||||||
The undocumented functions ``PyCFunction_GetFlags``
|
The undocumented functions ``PyCFunction_GetFlags``
|
||||||
and ``PyCFunction_GET_FLAGS``
|
and ``PyCFunction_GET_FLAGS``
|
||||||
|
@ -431,6 +444,15 @@ This PEP should not impact the performance of existing code
|
||||||
It is meant to allow efficient new code to be written,
|
It is meant to allow efficient new code to be written,
|
||||||
not to make existing code faster.
|
not to make existing code faster.
|
||||||
|
|
||||||
|
Here are a few pointers to the ``python-dev`` mailing list where
|
||||||
|
performance improvements are discussed:
|
||||||
|
|
||||||
|
- https://mail.python.org/pipermail/python-dev/2018-July/154571.html
|
||||||
|
|
||||||
|
- https://mail.python.org/pipermail/python-dev/2018-July/154740.html
|
||||||
|
|
||||||
|
- https://mail.python.org/pipermail/python-dev/2018-July/154775.html
|
||||||
|
|
||||||
|
|
||||||
Stable ABI
|
Stable ABI
|
||||||
==========
|
==========
|
||||||
|
@ -453,8 +475,8 @@ we are free to do that without restrictions.
|
||||||
Backwards compatibility
|
Backwards compatibility
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
There should be no difference at all for the Python interface,
|
There is no difference at all for the Python interface,
|
||||||
and neither for the documented C API
|
nor for the documented C API
|
||||||
(in the sense that all functions remain supported with the same functionality).
|
(in the sense that all functions remain supported with the same functionality).
|
||||||
|
|
||||||
The removed function ``PyCFunction_GetFlags``,
|
The removed function ``PyCFunction_GetFlags``,
|
||||||
|
@ -537,10 +559,10 @@ In the reference implementation, only the first of these uses the new code.
|
||||||
The other examples show that these kind of checks appear
|
The other examples show that these kind of checks appear
|
||||||
in multiple places, so it makes sense to add generic support for them.
|
in multiple places, so it makes sense to add generic support for them.
|
||||||
|
|
||||||
Why CCALL_SLICE_SELF?
|
Why CCALL_SELFARG?
|
||||||
---------------------
|
------------------
|
||||||
|
|
||||||
The flag ``CCALL_SLICE_SELF`` and the concept of self slicing
|
The flag ``CCALL_SELFARG`` and the concept of self slicing
|
||||||
are needed to support methods:
|
are needed to support methods:
|
||||||
the C function should not care
|
the C function should not care
|
||||||
whether it is called as unbound method or as bound method.
|
whether it is called as unbound method or as bound method.
|
||||||
|
@ -553,9 +575,9 @@ translate to the C call ``list_append([], 42)``.
|
||||||
|
|
||||||
Thanks to the proposed C call protocol, we can support this in such a way
|
Thanks to the proposed C call protocol, we can support this in such a way
|
||||||
that both the unbound and the bound method share a ``PyCCallDef``
|
that both the unbound and the bound method share a ``PyCCallDef``
|
||||||
structure (with the ``CCALL_SLICE_SELF`` flag set).
|
structure (with the ``CCALL_SELFARG`` flag set).
|
||||||
|
|
||||||
Concluding, ``CCALL_SLICE_SELF`` has two advantages:
|
Concluding, ``CCALL_SELFARG`` has two advantages:
|
||||||
there is no extra layer of indirection for calling
|
there is no extra layer of indirection for calling
|
||||||
and constructing bound methods does not require setting up a ``PyCCallDef`` structure.
|
and constructing bound methods does not require setting up a ``PyCCallDef`` structure.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue