[Python-checkins] bpo-36974: document PEP 590 (GH-13450)

Petr Viktorin webhook-mailer at python.org
Sun Jun 2 19:43:17 EDT 2019


https://github.com/python/cpython/commit/9e3e06e582accec82eb29cf665c3b4c7d84d2eb0
commit: 9e3e06e582accec82eb29cf665c3b4c7d84d2eb0
branch: master
author: Jeroen Demeyer <J.Demeyer at UGent.be>
committer: Petr Viktorin <encukou at gmail.com>
date: 2019-06-03T01:43:13+02:00
summary:

bpo-36974: document PEP 590 (GH-13450)

files:
M Doc/c-api/object.rst
M Doc/c-api/typeobj.rst
M Doc/includes/typestruct.h
M Doc/whatsnew/3.8.rst

diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst
index ffc35241e7a4..ce0d05942f4e 100644
--- a/Doc/c-api/object.rst
+++ b/Doc/c-api/object.rst
@@ -335,6 +335,83 @@ Object Protocol
    *NULL* on failure.
 
 
+.. c:function:: PyObject* _PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+
+   Call a callable Python object *callable*, using
+   :c:data:`vectorcall <PyTypeObject.tp_vectorcall_offset>` if possible.
+
+   *args* is a C array with the positional arguments.
+
+   *nargsf* is the number of positional arguments plus optionally the flag
+   :const:`PY_VECTORCALL_ARGUMENTS_OFFSET` (see below).
+   To get actual number of arguments, use
+   :c:func:`PyVectorcall_NARGS(nargsf) <PyVectorcall_NARGS>`.
+
+   *kwnames* can be either NULL (no keyword arguments) or a tuple of keyword
+   names. In the latter case, the values of the keyword arguments are stored
+   in *args* after the positional arguments.
+   The number of keyword arguments does not influence *nargsf*.
+
+   *kwnames* must contain only objects of type ``str`` (not a subclass),
+   and all keys must be unique.
+
+   Return the result of the call on success, or *NULL* on failure.
+
+   This uses the vectorcall protocol if the callable supports it;
+   otherwise, the arguments are converted to use
+   :c:member:`~PyTypeObject.tp_call`.
+
+   .. note::
+
+      This function is provisional and expected to become public in Python 3.9,
+      with a different name and, possibly, changed semantics.
+      If you use the function, plan for updating your code for Python 3.9.
+
+   .. versionadded:: 3.8
+
+.. c:var:: PY_VECTORCALL_ARGUMENTS_OFFSET
+
+   If set in a vectorcall *nargsf* argument, the callee is allowed to
+   temporarily change ``args[-1]``. In other words, *args* points to
+   argument 1 (not 0) in the allocated vector.
+   The callee must restore the value of ``args[-1]`` before returning.
+
+   Whenever they can do so cheaply (without additional allocation), callers
+   are encouraged to use :const:`PY_VECTORCALL_ARGUMENTS_OFFSET`.
+   Doing so will allow callables such as bound methods to make their onward
+   calls (which include a prepended *self* argument) cheaply.
+
+   .. versionadded:: 3.8
+
+.. c:function:: Py_ssize_t PyVectorcall_NARGS(size_t nargsf)
+
+   Given a vectorcall *nargsf* argument, return the actual number of
+   arguments.
+   Currently equivalent to ``nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET``.
+
+   .. versionadded:: 3.8
+
+.. c:function:: PyObject* _PyObject_FastCallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwdict)
+
+   Same as :c:func:`_PyObject_Vectorcall` except that the keyword arguments
+   are passed as a dictionary in *kwdict*. This may be *NULL* if there
+   are no keyword arguments.
+
+   For callables supporting :c:data:`vectorcall <PyTypeObject.tp_vectorcall_offset>`,
+   the arguments are internally converted to the vectorcall convention.
+   Therefore, this function adds some overhead compared to
+   :c:func:`_PyObject_Vectorcall`.
+   It should only be used if the caller already has a dictionary ready to use.
+
+   .. note::
+
+      This function is provisional and expected to become public in Python 3.9,
+      with a different name and, possibly, changed semantics.
+      If you use the function, plan for updating your code for Python 3.9.
+
+   .. versionadded:: 3.8
+
+
 .. c:function:: Py_hash_t PyObject_Hash(PyObject *o)
 
    .. index:: builtin: hash
diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
index e2f8f54be79a..83fcc5abed70 100644
--- a/Doc/c-api/typeobj.rst
+++ b/Doc/c-api/typeobj.rst
@@ -36,115 +36,115 @@ Quick Reference
 .. table::
    :widths: 18,18,18,1,1,1,1
 
-   +---------------------------------------------+-----------------------------------+-------------------+---------------+
-   | PyTypeObject Slot [#slots]_                 | :ref:`Type <slot-typedefs-table>` | special           | Info [#cols]_ |
-   |                                             |                                   | methods/attrs     +---+---+---+---+
-   |                                             |                                   |                   | O | T | D | I |
-   +=============================================+===================================+===================+===+===+===+===+
-   | <R> :c:member:`~PyTypeObject.tp_name`       | const char *                      | __name__          | X | X |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_basicsize`      | Py_ssize_t                        |                   | X | X |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_itemsize`       | Py_ssize_t                        |                   |   | X |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_dealloc`        | :c:type:`destructor`              |                   | X | X |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | (:c:member:`~PyTypeObject.tp_print`)        |                                                                       |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | (:c:member:`~PyTypeObject.tp_getattr`)      | :c:type:`getattrfunc`             | __getattribute__, |   |   |   | G |
-   |                                             |                                   | __getattr__       |   |   |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | (:c:member:`~PyTypeObject.tp_setattr`)      | :c:type:`setattrfunc`             | __setattr__,      |   |   |   | G |
-   |                                             |                                   | __delattr__       |   |   |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_as_async`       | :c:type:`PyAsyncMethods` *        | :ref:`sub-slots`  |   |   |   | % |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_repr`           | :c:type:`reprfunc`                | __repr__          | X | X |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_as_number`      | :c:type:`PyNumberMethods` *       | :ref:`sub-slots`  |   |   |   | % |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_as_sequence`    | :c:type:`PySequenceMethods` *     | :ref:`sub-slots`  |   |   |   | % |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_as_mapping`     | :c:type:`PyMappingMethods` *      | :ref:`sub-slots`  |   |   |   | % |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_hash`           | :c:type:`hashfunc`                | __hash__          | X |   |   | G |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_call`           | :c:type:`ternaryfunc`             | __call__          |   | X |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_str`            | :c:type:`reprfunc`                | __str__           | X |   |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_getattro`       | :c:type:`getattrofunc`            | __getattribute__, | X | X |   | G |
-   |                                             |                                   | __getattr__       |   |   |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_setattro`       | :c:type:`setattrofunc`            | __setattr__,      | X | X |   | G |
-   |                                             |                                   | __delattr__       |   |   |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_as_buffer`      | :c:type:`PyBufferProcs` *         |                   |   |   |   | % |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_flags`          | unsigned long                     |                   | X | X |   | ? |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_doc`            | const char *                      | __doc__           | X | X |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_traverse`       | :c:type:`traverseproc`            |                   |   | X |   | G |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_clear`          | :c:type:`inquiry`                 |                   |   | X |   | G |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_richcompare`    | :c:type:`richcmpfunc`             | __lt__,           | X |   |   | G |
-   |                                             |                                   | __le__,           |   |   |   |   |
-   |                                             |                                   | __eq__,           |   |   |   |   |
-   |                                             |                                   | __ne__,           |   |   |   |   |
-   |                                             |                                   | __gt__,           |   |   |   |   |
-   |                                             |                                   | __ge__            |   |   |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_weaklistoffset` | Py_ssize_t                        |                   |   | X |   | ? |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_iter`           | :c:type:`getiterfunc`             | __iter__          |   |   |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_iternext`       | :c:type:`iternextfunc`            | __next__          |   |   |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_methods`        | :c:type:`PyMethodDef` []          |                   | X | X |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_members`        | :c:type:`PyMemberDef` []          |                   |   | X |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_getset`         | :c:type:`PyGetSetDef` []          |                   | X | X |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_base`           | :c:type:`PyTypeObject` *          | __base__          |   |   | X |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_dict`           | :c:type:`PyObject` *              | __dict__          |   |   | ? |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_descr_get`      | :c:type:`descrgetfunc`            | __get__           |   |   |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_descr_set`      | :c:type:`descrsetfunc`            | __set__,          |   |   |   | X |
-   |                                             |                                   | __delete__        |   |   |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_dictoffset`     | Py_ssize_t                        |                   |   | X |   | ? |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_init`           | :c:type:`initproc`                | __init__          | X | X |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_alloc`          | :c:type:`allocfunc`               |                   | X |   | ? | ? |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_new`            | :c:type:`newfunc`                 | __new__           | X | X | ? | ? |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_free`           | :c:type:`freefunc`                |                   | X | X | ? | ? |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_is_gc`          | :c:type:`inquiry`                 |                   |   | X |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | <:c:member:`~PyTypeObject.tp_bases`>        | :c:type:`PyObject` *              | __bases__         |   |   | ~ |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | <:c:member:`~PyTypeObject.tp_mro`>          | :c:type:`PyObject` *              | __mro__           |   |   | ~ |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | [:c:member:`~PyTypeObject.tp_cache`]        | :c:type:`PyObject` *              |                   |   |   |       |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | [:c:member:`~PyTypeObject.tp_subclasses`]   | :c:type:`PyObject` *              | __subclasses__    |   |   |       |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | [:c:member:`~PyTypeObject.tp_weaklist`]     | :c:type:`PyObject` *              |                   |   |   |       |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | (:c:member:`~PyTypeObject.tp_del`)          | :c:type:`destructor`              |                   |   |   |   |   |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | [:c:member:`~PyTypeObject.tp_version_tag`]  | unsigned int                      |                   |   |   |       |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
-   | :c:member:`~PyTypeObject.tp_finalize`       | :c:type:`destructor`              | __del__           |   |   |   | X |
-   +---------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   +------------------------------------------------+-----------------------------------+-------------------+---------------+
+   | PyTypeObject Slot [#slots]_                    | :ref:`Type <slot-typedefs-table>` | special           | Info [#cols]_ |
+   |                                                |                                   | methods/attrs     +---+---+---+---+
+   |                                                |                                   |                   | O | T | D | I |
+   +================================================+===================================+===================+===+===+===+===+
+   | <R> :c:member:`~PyTypeObject.tp_name`          | const char *                      | __name__          | X | X |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_basicsize`         | Py_ssize_t                        |                   | X | X |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_itemsize`          | Py_ssize_t                        |                   |   | X |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_dealloc`           | :c:type:`destructor`              |                   | X | X |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_vectorcall_offset` | Py_ssize_t                        |                   |   |   |   | ? |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | (:c:member:`~PyTypeObject.tp_getattr`)         | :c:type:`getattrfunc`             | __getattribute__, |   |   |   | G |
+   |                                                |                                   | __getattr__       |   |   |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | (:c:member:`~PyTypeObject.tp_setattr`)         | :c:type:`setattrfunc`             | __setattr__,      |   |   |   | G |
+   |                                                |                                   | __delattr__       |   |   |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_as_async`          | :c:type:`PyAsyncMethods` *        | :ref:`sub-slots`  |   |   |   | % |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_repr`              | :c:type:`reprfunc`                | __repr__          | X | X |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_as_number`         | :c:type:`PyNumberMethods` *       | :ref:`sub-slots`  |   |   |   | % |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_as_sequence`       | :c:type:`PySequenceMethods` *     | :ref:`sub-slots`  |   |   |   | % |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_as_mapping`        | :c:type:`PyMappingMethods` *      | :ref:`sub-slots`  |   |   |   | % |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_hash`              | :c:type:`hashfunc`                | __hash__          | X |   |   | G |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_call`              | :c:type:`ternaryfunc`             | __call__          |   | X |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_str`               | :c:type:`reprfunc`                | __str__           | X |   |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_getattro`          | :c:type:`getattrofunc`            | __getattribute__, | X | X |   | G |
+   |                                                |                                   | __getattr__       |   |   |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_setattro`          | :c:type:`setattrofunc`            | __setattr__,      | X | X |   | G |
+   |                                                |                                   | __delattr__       |   |   |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_as_buffer`         | :c:type:`PyBufferProcs` *         |                   |   |   |   | % |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_flags`             | unsigned long                     |                   | X | X |   | ? |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_doc`               | const char *                      | __doc__           | X | X |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_traverse`          | :c:type:`traverseproc`            |                   |   | X |   | G |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_clear`             | :c:type:`inquiry`                 |                   |   | X |   | G |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_richcompare`       | :c:type:`richcmpfunc`             | __lt__,           | X |   |   | G |
+   |                                                |                                   | __le__,           |   |   |   |   |
+   |                                                |                                   | __eq__,           |   |   |   |   |
+   |                                                |                                   | __ne__,           |   |   |   |   |
+   |                                                |                                   | __gt__,           |   |   |   |   |
+   |                                                |                                   | __ge__            |   |   |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_weaklistoffset`    | Py_ssize_t                        |                   |   | X |   | ? |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_iter`              | :c:type:`getiterfunc`             | __iter__          |   |   |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_iternext`          | :c:type:`iternextfunc`            | __next__          |   |   |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_methods`           | :c:type:`PyMethodDef` []          |                   | X | X |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_members`           | :c:type:`PyMemberDef` []          |                   |   | X |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_getset`            | :c:type:`PyGetSetDef` []          |                   | X | X |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_base`              | :c:type:`PyTypeObject` *          | __base__          |   |   | X |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_dict`              | :c:type:`PyObject` *              | __dict__          |   |   | ? |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_descr_get`         | :c:type:`descrgetfunc`            | __get__           |   |   |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_descr_set`         | :c:type:`descrsetfunc`            | __set__,          |   |   |   | X |
+   |                                                |                                   | __delete__        |   |   |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_dictoffset`        | Py_ssize_t                        |                   |   | X |   | ? |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_init`              | :c:type:`initproc`                | __init__          | X | X |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_alloc`             | :c:type:`allocfunc`               |                   | X |   | ? | ? |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_new`               | :c:type:`newfunc`                 | __new__           | X | X | ? | ? |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_free`              | :c:type:`freefunc`                |                   | X | X | ? | ? |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_is_gc`             | :c:type:`inquiry`                 |                   |   | X |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | <:c:member:`~PyTypeObject.tp_bases`>           | :c:type:`PyObject` *              | __bases__         |   |   | ~ |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | <:c:member:`~PyTypeObject.tp_mro`>             | :c:type:`PyObject` *              | __mro__           |   |   | ~ |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | [:c:member:`~PyTypeObject.tp_cache`]           | :c:type:`PyObject` *              |                   |   |   |       |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | [:c:member:`~PyTypeObject.tp_subclasses`]      | :c:type:`PyObject` *              | __subclasses__    |   |   |       |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | [:c:member:`~PyTypeObject.tp_weaklist`]        | :c:type:`PyObject` *              |                   |   |   |       |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | (:c:member:`~PyTypeObject.tp_del`)             | :c:type:`destructor`              |                   |   |   |   |   |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | [:c:member:`~PyTypeObject.tp_version_tag`]     | unsigned int                      |                   |   |   |       |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
+   | :c:member:`~PyTypeObject.tp_finalize`          | :c:type:`destructor`              | __del__           |   |   |   | X |
+   +------------------------------------------------+-----------------------------------+-------------------+---+---+---+---+
 
 If :const:`COUNT_ALLOCS` is defined then the following (internal-only)
 fields exist as well:
@@ -364,12 +364,6 @@ slot typedefs
 +-----------------------------+-----------------------------+----------------------+
 | :c:type:`reprfunc`          | :c:type:`PyObject` *        | :c:type:`PyObject` * |
 +-----------------------------+-----------------------------+----------------------+
-| :c:type:`printfunc`         | .. line-block::             | int                  |
-|                             |                             |                      |
-|                             |    :c:type:`PyObject` *     |                      |
-|                             |    FILE *                   |                      |
-|                             |    int                      |                      |
-+-----------------------------+-----------------------------+----------------------+
 | :c:type:`getattrfunc`       | .. line-block::             | :c:type:`PyObject` * |
 |                             |                             |                      |
 |                             |    :c:type:`PyObject` *     |                      |
@@ -675,9 +669,66 @@ and :c:type:`PyType_Type` effectively act as defaults.)
    This field is inherited by subtypes.
 
 
-.. c:member:: printfunc PyTypeObject.tp_print
+.. c:member:: Py_ssize_t PyTypeObject.tp_vectorcall_offset
+
+   An optional offset to a per-instance function that implements calling
+   the object using the *vectorcall* protocol, a more efficient alternative
+   of the simpler :c:member:`~PyTypeObject.tp_call`.
+
+   This field is only used if the flag :const:`_Py_TPFLAGS_HAVE_VECTORCALL`
+   is set. If so, this must be a positive integer containing the offset in the
+   instance of a :c:type:`vectorcallfunc` pointer.
+   The signature is the same as for :c:func:`_PyObject_Vectorcall`::
+
+        PyObject *vectorcallfunc(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+
+   The *vectorcallfunc* pointer may be zero, in which case the instance behaves
+   as if :const:`_Py_TPFLAGS_HAVE_VECTORCALL` was not set: calling the instance
+   falls back to :c:member:`~PyTypeObject.tp_call`.
+
+   Any class that sets ``_Py_TPFLAGS_HAVE_VECTORCALL`` must also set
+   :c:member:`~PyTypeObject.tp_call` and make sure its behaviour is consistent
+   with the *vectorcallfunc* function.
+   This can be done by setting *tp_call* to ``PyVectorcall_Call``:
+
+   .. c:function:: PyObject *PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict)
+
+      Call *callable*'s *vectorcallfunc* with positional and keyword
+      arguments given in a tuple and dict, respectively.
+
+      This function is intended to be used in the ``tp_call`` slot.
+      It does not fall back to ``tp_call`` and it currently does not check the
+      ``_Py_TPFLAGS_HAVE_VECTORCALL`` flag.
+      To call an object, use one of the :c:func:`PyObject_Call <PyObject_Call>`
+      functions instead.
+
+   .. note::
+
+      It is not recommended for :ref:`heap types <heap-types>` to implement
+      the vectorcall protocol.
+      When a user sets ``__call__`` in Python code, only ``tp_call`` is updated,
+      possibly making it inconsistent with the vectorcall function.
+
+   .. note::
+
+      The semantics of the ``tp_vectorcall_offset`` slot are provisional and
+      expected to be finalized in Python 3.9.
+      If you use vectorcall, plan for updating your code for Python 3.9.
+
+   .. versionchanged:: 3.8
+
+      This slot was used for print formatting in Python 2.x.
+      In Python 3.0 to 3.7, it was reserved and named ``tp_print``.
 
-   Reserved slot, formerly used for print formatting in Python 2.x.
+   **Inheritance:**
+
+   This field is inherited by subtypes together with
+   :c:member:`~PyTypeObject.tp_call`: a subtype inherits
+   :c:member:`~PyTypeObject.tp_vectorcall_offset` from its base type when
+   the subtype’s :c:member:`~PyTypeObject.tp_call` is NULL.
+
+   Note that `heap types`_ (including subclasses defined in Python) do not
+   inherit the :const:`_Py_TPFLAGS_HAVE_VECTORCALL` flag.
 
 
 .. c:member:: getattrfunc PyTypeObject.tp_getattr
@@ -1104,6 +1155,28 @@ and :c:type:`PyType_Type` effectively act as defaults.)
          :c:member:`~PyTypeObject.tp_finalize` slot is always present in the
          type structure.
 
+   .. data:: _Py_TPFLAGS_HAVE_VECTORCALL
+
+      This bit is set when the class implements the vectorcall protocol.
+      See :c:member:`~PyTypeObject.tp_vectorcall_offset` for details.
+
+      **Inheritance:**
+
+      This bit is set on *static* subtypes if ``tp_flags`` is not overridden:
+      a subtype inherits ``_Py_TPFLAGS_HAVE_VECTORCALL`` from its base type
+      when the subtype’s :c:member:`~PyTypeObject.tp_call` is NULL
+      and the subtype's ``Py_TPFLAGS_HEAPTYPE`` is not set.
+
+      `Heap types`_ do not inherit ``_Py_TPFLAGS_HAVE_VECTORCALL``.
+
+      .. note::
+
+         This flag is provisional and expected to become public in Python 3.9,
+         with a different name and, possibly, changed semantics.
+         If you use vectorcall, plan for updating your code for Python 3.9.
+
+      .. versionadded:: 3.8
+
 
 .. c:member:: const char* PyTypeObject.tp_doc
 
@@ -2286,6 +2359,14 @@ Slot Type typedefs
 
 .. c:type:: void (*destructor)(PyObject *)
 
+.. c:type:: PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+
+   See :c:member:`~PyTypeObject.tp_vectorcall_offset`.
+
+   Arguments to ``vectorcallfunc`` are the same as for :c:func:`_PyObject_Vectorcall`.
+
+   .. versionadded:: 3.8
+
 .. c:type:: void (*freefunc)(void *)
 
    See :c:member:`~PyTypeObject.tp_free`.
@@ -2302,10 +2383,6 @@ Slot Type typedefs
 
    See :c:member:`~PyTypeObject.tp_repr`.
 
-.. c:type:: int (*printfunc)(PyObject *, FILE *, int)
-
-   This is hidden if :const:`PY_LIMITED_API` is set.
-
 .. c:type:: PyObject *(*getattrfunc)(PyObject *self, char *attr)
 
    Return the value of the named attribute for the object.
@@ -2409,7 +2486,7 @@ with a more verbose initializer::
        sizeof(MyObject),               /* tp_basicsize */
        0,                              /* tp_itemsize */
        (destructor)myobj_dealloc,      /* tp_dealloc */
-       0,                              /* tp_print */
+       0,                              /* tp_vectorcall_offset */
        0,                              /* tp_getattr */
        0,                              /* tp_setattr */
        0,                              /* tp_as_async */
diff --git a/Doc/includes/typestruct.h b/Doc/includes/typestruct.h
index 9f47899a198e..9ada03cfc4a4 100644
--- a/Doc/includes/typestruct.h
+++ b/Doc/includes/typestruct.h
@@ -6,7 +6,7 @@ typedef struct _typeobject {
     /* Methods to implement standard operations */
 
     destructor tp_dealloc;
-    printfunc tp_print;
+    Py_ssize_t tp_vectorcall_offset;
     getattrfunc tp_getattr;
     setattrfunc tp_setattr;
     PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index e9c9c814c69a..9474a2f4aafe 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -238,6 +238,22 @@ See :pep:`587` for a full description.
 (Contributed by Victor Stinner in :issue:`36763`.)
 
 
+Vectorcall: a fast calling protocol for CPython
+-----------------------------------------------
+
+The "vectorcall" protocol is added to the Python/C API.
+It is meant to formalize existing optimizations which were already done
+for various classes.
+Any extension type implementing a callable can use this protocol.
+
+This is currently provisional,
+the aim is to make it fully public in Python 3.9.
+
+See :pep:`590` for a full description.
+
+(Contributed by Jeroen Demeyer and Mark Shannon in :issue:`36974`.)
+
+
 Other Language Changes
 ======================
 



More information about the Python-checkins mailing list