PEP 580: minor update (#749)

This commit is contained in:
jdemeyer 2018-07-30 17:02:03 +02:00 committed by Chris Angelico
parent 3bdd70578a
commit 84871930a5
1 changed files with 61 additions and 39 deletions

View File

@ -23,7 +23,7 @@ this new protocol is used for the existing classes
``builtin_function_or_method`` and ``method_descriptor``.
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.
@ -177,28 +177,34 @@ Its precise signature depends on flags.
Below are the possible values for ``cc_flags & CCALL_SIGNATURE``
together with the arguments that the C function takes.
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:
- ``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)``
(the function takes no arguments but a ``NULL`` is passed to the C function)
- ``CCALL_NOARGS``:
``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.
If so, the C function takes an additional argument as first argument
which is the function object (the ``self`` in ``__call__``).
If so, the C function takes an additional argument as second argument
after ``self``.
This argument is used to pass the function object (the ``self`` in ``__call__``).
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
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)``
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,
the ``CCALL_...`` constants do not necessarily represent single bits.
So checking ``(cc_flags & CCALL_VARARGS) == 0`` is not a valid way
@ -230,18 +240,18 @@ If not, a ``TypeError`` is raised.
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 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
``args`` and instead passed as first argument to the C function.
Effectively, the first positional argument is treated as ``__self__``.
If there are no positional arguments, ``TypeError`` is raised.
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
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
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`` and ``PyEval_GetFuncDesc``
use borrowed references to the ``__name__`` attribute.
This is required because ``PyEval_GetFuncName``
uses a borrowed reference to the ``__name__`` attribute.
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)``:
return true if ``op`` implements the C call protocol.
@ -309,12 +320,12 @@ All the functions and macros below
apply to any instance supporting the C call protocol.
In other words, ``PyCCall_Check(func)`` must be true.
- ``PyObject * PyCCall_Call(PyObject *func, PyObject *args, PyObject *kwds)``:
- ``PyObject *PyCCall_Call(PyObject *func, PyObject *args, PyObject *kwds)``:
call ``func`` with positional arguments ``args``
and keyword arguments ``kwds`` (``kwds`` may be NULL).
This function is meant to be put in the ``tp_call`` slot.
- ``PyObject * PyCCall_FASTCALL(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwds)``:
- ``PyObject *PyCCall_FASTCALL(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwds)``:
call ``func`` with ``nargs`` positional arguments given by ``args[0]``, …, ``args[nargs-1]``.
The parameter ``kwds`` can be NULL (no keyword arguments),
a dict with ``name:value`` items or a tuple with keyword names.
@ -323,33 +334,29 @@ In other words, ``PyCCall_Check(func)`` must be true.
Macros to access the ``PyCCallRoot`` and ``PyCCallDef`` structures:
- ``PyCCallRoot * PyCCall_CCALLROOT(PyObject *func)``:
- ``PyCCallRoot *PyCCall_CCALLROOT(PyObject *func)``:
pointer to the ``PyCCallRoot`` structure inside ``func``.
- ``PyCCallDef * PyCCall_CCALLDEF(PyObject *func)``:
- ``PyCCallDef *PyCCall_CCALLDEF(PyObject *func)``:
shorthand for ``PyCCall_CCALLROOT(func)->cr_ccall``.
- ``PyCCallDef * PyCCall_FLAGS(PyObject *func)``:
- ``PyCCallDef *PyCCall_FLAGS(PyObject *func)``:
shorthand for ``PyCCall_CCALLROOT(func)->cr_ccall->cc_flags``.
- ``PyObject * PyCCall_SELF(PyOject *func)``:
- ``PyObject *PyCCall_SELF(PyOject *func)``:
shorthand for ``PyCCall_CCALLROOT(func)->cr_self``.
Generic getters, meant to be put into the ``tp_getset`` array:
- ``PyObject * PyCCall_GenericGetParent(PyObject *func, void *closure)``:
- ``PyObject *PyCCall_GenericGetParent(PyObject *func, void *closure)``:
return ``cc_parent``.
Raise ``AttributeError`` if ``cc_parent`` is NULL.
- ``PyObject * PyCCall_GenericGetQualname(PyObject *func, void *closure)``:
- ``PyObject *PyCCall_GenericGetQualname(PyObject *func, void *closure)``:
return a string suitable for using as ``__qualname__``.
This uses the ``__qualname__`` of ``cc_parent`` if possible.
It also uses the ``__name__`` attribute.
- ``PyObject * PyCCall_GenericGetSelf(PyObject *func, void *closure)``:
return ``cr_self``.
Raise ``AttributeError`` if ``cr_self`` is NULL.
Profiling
---------
@ -374,7 +381,7 @@ the implementation becomes very similar, but they remain separate classes
The ``PyCCallDef`` structure is simply stored
as part of the object structure.
Both classes use ``PyCFunctionObject`` as object structure.
This is the new layout::
This is the new layout for both classes::
typedef struct {
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)``:
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``
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,
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
==========
@ -453,8 +475,8 @@ we are free to do that without restrictions.
Backwards compatibility
=======================
There should be no difference at all for the Python interface,
and neither for the documented C API
There is no difference at all for the Python interface,
nor for the documented C API
(in the sense that all functions remain supported with the same functionality).
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
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:
the C function should not care
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
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
and constructing bound methods does not require setting up a ``PyCCallDef`` structure.