PEP 590: minor edits (#973)
This commit is contained in:
parent
ad9c99dd8d
commit
92f4dbdbf1
44
pep-0590.rst
44
pep-0590.rst
|
@ -59,10 +59,10 @@ Changes to the ``PyTypeObject``
|
|||
-------------------------------
|
||||
|
||||
The a new slot called ``tp_vectorcall_offset`` is added. It has the type ``uint32_t``.
|
||||
A new flag is added, ``Py_TPFLAGS_HAVE_VECTOR_CALL``, which is set for any new PyTypeObjects that include the
|
||||
A new flag is added, ``Py_TPFLAGS_HAVE_VECTORCALL``, which is set for any new PyTypeObjects that include the
|
||||
``tp_vectorcall_offset`` member.
|
||||
|
||||
If ``Py_TPFLAGS_HAS_VECTORCALL`` is set then ``tp_vectorcall_offset`` is the offset
|
||||
If ``Py_TPFLAGS_HAVE_VECTORCALL`` is set then ``tp_vectorcall_offset`` is the offset
|
||||
into the object of the ``vectorcall`` function-pointer.
|
||||
|
||||
The unused slot ``printfunc tp_print`` is replaced with ``vectorcall tp_vectorcall``, so that classes
|
||||
|
@ -71,21 +71,21 @@ can support the vectorcall calling convention.
|
|||
Additional flags
|
||||
----------------
|
||||
|
||||
One additional flag is specified: ``PY_METHOD_DESCRIPTOR``.
|
||||
One additional flag is specified: ``Py_TPFLAGS_METHOD_DESCRIPTOR``.
|
||||
|
||||
``PY_METHOD_DESCRIPTOR`` should be set if the the callable uses the descriptor protocol to create a method or method-like object.
|
||||
``Py_TPFLAGS_METHOD_DESCRIPTOR`` should be set if the the callable uses the descriptor protocol to create a method or method-like object.
|
||||
This is used by the interpreter to avoid creating temporary objects when calling methods.
|
||||
|
||||
If this flag is set for a class ``F``, then instances of that class are expected to behave the same as a Python function when used as a class attribute.
|
||||
Specifically, this mean that the value of ``c.m`` where ``C.m`` is an instanceof the class ``F`` (and ``c`` is an instance of ``C``)
|
||||
must be an object that acts like a bound-method binding ``C.m`` and ``c``.
|
||||
Specifically, this means that the value of ``c.m`` where ``C.m`` is an instance of the class ``F`` (and ``c`` is an instance of ``C``)
|
||||
must be an object that acts like a bound method binding ``C.m`` and ``c``.
|
||||
This flag is necessary if custom callables are to be able to behave like Python functions *and* be called as efficiently as Python or built-in functions.
|
||||
|
||||
The call
|
||||
--------
|
||||
|
||||
The call takes the form ``((vectorcall)(((char *)o)+offset))(o, n, args, kwnames)`` where
|
||||
``offset`` is ``TYPE(o)->tp_vectorcall``
|
||||
``offset`` is ``Py_TYPE(o)->tp_vectorcall_offset``.
|
||||
The caller is responsible for creating the ``kwnames`` tuple and ensuring that there are no duplicates in it.
|
||||
``n`` is the number of postional arguments plus ``PY_VECTORCALL_ARGUMENTS_OFFSET`` if the argument vector pointer points to argument 1 in the
|
||||
allocated vector.
|
||||
|
@ -94,7 +94,7 @@ allocated vector.
|
|||
Example of how ``PY_VECTORCALL_ARGUMENTS_OFFSET`` is used by a callee to avoid allocation [3]_
|
||||
|
||||
Whenever they can do so cheaply (without allocation) callers are encouraged to offset the arguments.
|
||||
Doing so will allow callables such as bound-methods to make their onward calls cheaply.
|
||||
Doing so will allow callables such as bound methods to make their onward calls cheaply.
|
||||
The interpreter already allocates space on the stack for the callable, so it can offset its arguments for no additional cost.
|
||||
|
||||
Continued prohibition of callable classes as base classes
|
||||
|
@ -107,7 +107,7 @@ If callables could be sub-classed then any call to a ``function`` or a ``method_
|
|||
New C API and changes to CPython
|
||||
================================
|
||||
|
||||
``PyObject *PyObject_VectorCallWithCallable(PyObject *func, PyObject **args, Py_ssize_t nargs, PyTupleObject *kwnames)``
|
||||
``PyObject *PyObject_VectorCallWithCallable(PyObject *obj, PyObject **args, Py_ssize_t nargs, PyTupleObject *kwnames)``
|
||||
Calls ``obj`` with the given arguments.
|
||||
Note that ``nargs`` is the number of positional arguments; no offsetting is allowed.
|
||||
|
||||
|
@ -118,16 +118,16 @@ Note that ``nargs`` is the number of positional arguments, including the callabl
|
|||
Both functions raise an exception if ``obj`` is not callable.
|
||||
|
||||
Two utility functions are provided to call the new calling convention from the old one, or vice-versa.
|
||||
These functions are ``PyObject *``PyCall_MakeVectorCall(PyObject *obj, PyObject *tuple, PyObject **dict);`` and
|
||||
``PyObject *PyCall_MakeTpCall(PyObject *obj, PyObject **args, Py_ssize_t nargs, PyTupleObject *kwnames);``, respectively.
|
||||
These functions are ``PyObject *PyCall_MakeVectorCall(PyObject *obj, PyObject *tuple, PyObject **dict)`` and
|
||||
``PyObject *PyCall_MakeTpCall(PyObject *obj, PyObject **args, Py_ssize_t nargs, PyTupleObject *kwnames)``, respectively.
|
||||
|
||||
Both functions raise an exception if ``obj`` does not support the relevant protocol.
|
||||
|
||||
``METH_FASTCALL`` and ``METH_VECTORCALL`` flags
|
||||
-----------------------------------------------
|
||||
|
||||
A new ``METH_VECTORCALL`` flag is added for specifying ``MethodDef`` structs. It is equivalent to the currently undocumented ``METH_FASTCALL | METH_KEYWORD`` flag.
|
||||
The new flag specifies that the function has the type ``PyObject *(*call) (PyObject * self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwname)``
|
||||
A new ``METH_VECTORCALL`` flag is added for specifying ``PyMethodDef`` structs. It is equivalent to the currently undocumented ``METH_FASTCALL | METH_KEYWORD`` flags.
|
||||
The new flag specifies that the function has the type ``PyObject *(*call) (PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwname)``
|
||||
|
||||
Internal CPython changes
|
||||
========================
|
||||
|
@ -155,12 +155,12 @@ Third-party built-in classes using the new extended call interface
|
|||
------------------------------------------------------------------
|
||||
|
||||
To enable call performance on a par with Python functions and built-in functions, third-party callables should include a ``vectorcall`` function pointer
|
||||
and set ``tp_vectorcall`` to the correct value.
|
||||
Any class the sets ``tp_vectorcall`` to non-zero should also implement the ``tp_call`` function and make sure its behaviour is consistent with the ``vectorcall`` function.
|
||||
and set ``tp_vectorcall_offset`` to the correct value.
|
||||
Any class that sets ``tp_vectorcall_offset`` to non-zero should also implement the ``tp_call`` function and make sure its behaviour is consistent with the ``vectorcall`` function.
|
||||
Setting ``tp_call`` to ``PyCall_MakeVectorCall`` will suffice.
|
||||
|
||||
The `MethodDef` protocol and Argument Clinic
|
||||
============================================
|
||||
The ``PyMethodDef`` protocol and Argument Clinic
|
||||
================================================
|
||||
|
||||
Argument Clinic [4]_ automatically generates wrapper functions around lower-level callables, providing safe unboxing of primitive types and
|
||||
other safety checks.
|
||||
|
@ -190,20 +190,18 @@ This PEP is broader in scope than PEP 576 and uses variable rather than fixed of
|
|||
The underlying calling convention is similar. Because PEP 576 only allows a fixed offset for the function pointer,
|
||||
it would not allow the improvements to any objects with constraints on their layout.
|
||||
|
||||
PEP 580 proposes a major change to the `MethodDef` protocol used to define builtin functions.
|
||||
PEP 580 proposes a major change to the ``PyMethodDef`` protocol used to define builtin functions.
|
||||
This PEP provides a more general and simpler mechanism in the form of a new calling convention.
|
||||
This PEP also extends the `MethodDef` protocol, but merely to formalise existing conventions.
|
||||
PEP 580 is specifically targetted at function-like objects, and doesn't support other callables like classes, partial functions,
|
||||
or proxies.
|
||||
This PEP also extends the ``PyMethodDef`` protocol, but merely to formalise existing conventions.
|
||||
|
||||
Other rejected approaches
|
||||
-------------------------
|
||||
|
||||
A longer, 6 argument, form combining both the vector and optional tuple and dictionary arguments was considered.
|
||||
However, it was found that the code to convert between it and the old `tp_call` form was overly cumbersome and inefficient.
|
||||
However, it was found that the code to convert between it and the old ``tp_call`` form was overly cumbersome and inefficient.
|
||||
Also, since only 4 arguments are passed in registers on x64 Windows, the two extra arguments would have non-neglible costs.
|
||||
|
||||
Removing any special cases and making all calls use the `tp_call` form was also considered.
|
||||
Removing any special cases and making all calls use the ``tp_call`` form was also considered.
|
||||
However, unless a much more efficient way was found to create and destroy tuples, and to a lesser extent dictionaries,
|
||||
then it would be too slow.
|
||||
|
||||
|
|
Loading…
Reference in New Issue