Update PEP 575 (#606)

This commit is contained in:
jdemeyer 2018-04-03 21:52:34 +02:00 committed by Chris Angelico
parent 5af613bbb2
commit 82f02c930a
1 changed files with 46 additions and 37 deletions

View File

@ -19,7 +19,7 @@ Mainly, make built-in functions behave more like Python functions
without sacrificing performance. without sacrificing performance.
A new base class ``basefunction`` is introduced and the various function A new base class ``basefunction`` is introduced and the various function
classes, as well as ``method``, inherit from it. classes, as well as ``method`` (renamed to ``bound_method``), inherit from it.
We also allow subclassing of some of these function classes. We also allow subclassing of some of these function classes.
@ -68,13 +68,13 @@ This is the new class hierarchy for functions and methods::
builtin_function (*) | \ builtin_function (*) | \
| python_function | python_function
| |
method (*) bound_method (*)
The two classes marked with (*) do *not* allow subclassing; The two classes marked with (*) do *not* allow subclassing;
the others do. the others do.
There is no difference between functions and unbound methods, There is no difference between functions and unbound methods,
while bound methods are instances of ``method``. while bound methods are instances of ``bound_method``.
basefunction basefunction
------------ ------------
@ -88,10 +88,11 @@ with some differences:
If the ``__self__`` attribute was already set, then this is a no-op: If the ``__self__`` attribute was already set, then this is a no-op:
the existing function is returned instead. the existing function is returned instead.
#. A new read-only slot ``__objclass__``, represented in the C structure as ``m_selftype``. #. A new read-only slot ``__objclass__``, represented in the C structure as ``m_objclass``.
If this attribute exists, it must be a class (it cannot be ``None``). If this attribute exists, it must be an extension type.
If so, the function must be called with ``self`` being an instance of that class. If so, the function must be called with ``self`` being an instance of that class.
This is meant to support unbound methods of extension types, replacing ``method_descriptor``. This is meant to support unbound methods of extension types, replacing ``method_descriptor``.
The pointer ``m_objclass`` is not considered a reference.
#. Argument Clinic [#clinic]_ is not supported. #. Argument Clinic [#clinic]_ is not supported.
@ -108,7 +109,7 @@ with some differences:
#. A new flag ``METH_ARG0_NO_SLICE`` for ``ml_flags``. #. A new flag ``METH_ARG0_NO_SLICE`` for ``ml_flags``.
If this flag is *not* set, ``__objclass__`` is set and ``__self__`` is not set, If this flag is *not* set, ``__objclass__`` is set and ``__self__`` is not set,
then the first positional argument is treated as ``__self__``. then the first positional argument is treated as ``__self__``.
For more details, see `Calling basefunction instances`_. For more details, see `Self slicing`_.
#. A new flag ``METH_PYTHON`` for ``ml_flags``. #. A new flag ``METH_PYTHON`` for ``ml_flags``.
This flag indicates that this function should be treated as Python function. This flag indicates that this function should be treated as Python function.
@ -135,18 +136,16 @@ These are the relevant C structures::
PyObject *m_self; /* __self__: anything, can be NULL; readonly */ PyObject *m_self; /* __self__: anything, can be NULL; readonly */
PyObject *m_module; /* __module__: anything */ PyObject *m_module; /* __module__: anything */
PyObject *m_weakreflist; /* List of weak references */ PyObject *m_weakreflist; /* List of weak references */
PyObject *m_selftype; /* __objclass__: type object or NULL; readonly */ PyTypeObject *m_objclass; /* __objclass__: type or NULL; readonly */
} PyBaseFunctionObject; } PyBaseFunctionObject;
typedef struct { typedef struct {
const char *ml_name; /* The name of the built-in function/method */ const char *ml_name; /* The name of the built-in function/method */
PyCFunction ml_meth; /* The C function that implements it */ PyCFunction ml_meth; /* The C function that implements it */
uint32_t ml_flags; /* Combination of METH_xxx flags, which mostly int ml_flags; /* Combination of METH_xxx flags, which mostly
describe the args expected by the C func */ describe the args expected by the C func */
} PyCFunctionDef; } PyCFunctionDef;
Note that the type of ``ml_flags`` was changed from ``int`` to
``uint32_t`` (it makes a lot of sense to fix the number of bits).
Subclasses may extend ``PyCFunctionDef`` with extra fields. Subclasses may extend ``PyCFunctionDef`` with extra fields.
builtin_function builtin_function
@ -162,10 +161,13 @@ This is a copy of ``basefunction``, with the following differences:
typedef struct { typedef struct {
const char *ml_name; const char *ml_name;
PyCFunction ml_meth; PyCFunction ml_meth;
uint32_t ml_flags; int ml_flags;
const char *ml_doc; const char *ml_doc;
} PyMethodDef; } PyMethodDef;
Note that ``PyMethodDef`` is part of the Python Stable ABI [#ABI]_,
so we cannot change this structure.
#. Argument Clinic [#clinic]_ is supported. #. Argument Clinic [#clinic]_ is supported.
The type object is ``PyTypeObject PyCFunction_Type`` The type object is ``PyTypeObject PyCFunction_Type``
@ -243,14 +245,18 @@ However, it is not required that ``base.m_ml`` points to ``_ml``.
The constructor takes care of setting up ``base.m_ml``. The constructor takes care of setting up ``base.m_ml``.
In particular, it sets the ``METH_PYTHON`` flag. In particular, it sets the ``METH_PYTHON`` flag.
method bound_method
------ ------------
The class ``method`` is used for all bound methods, The class ``bound_method`` is used for all bound methods,
regardless of the class of the underlying function. regardless of the class of the underlying function.
There is one extra attribute ``__func__`` pointing to that function. It adds one new attribute on top of ``basefunction``:
``__func__`` points to that function.
For methods, there is a complication because we want to allow ``bound_method`` replaces the old ``method`` class
which was used only for Python functions bound as method.
There is a complication because we want to allow
constructing a method from a arbitrary callable which constructing a method from a arbitrary callable which
may not be an instance of ``basefunction``. may not be an instance of ``basefunction``.
Therefore, in practice there are two kinds of methods: Therefore, in practice there are two kinds of methods:
@ -295,7 +301,7 @@ If not, a ``TypeError`` is raised.
Flags Flags
----- -----
For convenience, we define two new constants: For convenience, we define a new constant:
``METH_CALLSIGNATURE`` combines the flags from ``PyCFunctionDef.ml_flags`` ``METH_CALLSIGNATURE`` combines the flags from ``PyCFunctionDef.ml_flags``
which specify the signature of the C function to be called. which specify the signature of the C function to be called.
It is equal to :: It is equal to ::
@ -306,14 +312,22 @@ Exactly one of the first four flags above must be set
and only ``METH_VARARGS`` and ``METH_FASTCALL`` may be combined with ``METH_KEYWORDS``. and only ``METH_VARARGS`` and ``METH_FASTCALL`` may be combined with ``METH_KEYWORDS``.
Violating these rules is undefined behaviour. Violating these rules is undefined behaviour.
The second new constant is ``METH_CALLFLAGS``. There are two more flags which affect calling functions:
It combines all flags which influence how a function is called. ``METH_ARG0_FUNCTION`` and ``METH_ARG0_NO_SLICE``.
It is equal to ::
METH_CALLSIGNATURE | METH_ARG0_FUNCTION | METH_ARG0_NO_SLICE Some flags are already documented in [#methoddoc]_.
We explain the others shortly.
Some of these flags are already documented [#methoddoc]_. Self slicing
We explain the others below. ------------
If the function has a ``__objclass__`` attribute, no ``__self__``
attribute and neither ``METH_ARG0_FUNCTION`` nor ``METH_ARG0_NO_SLICE`` is set,
then the first positional argument (which must exist because of ``__objclass__``)
is removed from ``*args`` and instead passed as first argument to the C function.
Effectively, the first positional argument is treated as ``__self__``.
This process is called "self slicing".
This does not affect keyword arguments.
METH_FASTCALL METH_FASTCALL
------------- -------------
@ -348,14 +362,7 @@ by getting it from the function, for example using ``PyBaseFunction_GET_SELF``.
METH_ARG0_NO_SLICE METH_ARG0_NO_SLICE
------------------ ------------------
If the function has a ``__objclass__`` attribute, no ``__self__`` The flag ``METH_ARG0_NO_SLICE`` disables self slicing.
attribute and neither ``METH_ARG0_FUNCTION`` nor ``METH_ARG0_NO_SLICE`` are set,
then the first positional argument (which must exist because of ``__objclass__``)
is removed from ``*args`` and instead passed as first argument to the C function.
Effectively, the first positional argument is treated as ``__self__``.
This process is called "self slicing".
This does not affect keyword arguments.
It is not allowed to combine the flags ``METH_ARG0_FUNCTION`` and ``METH_ARG0_NO_SLICE``. It is not allowed to combine the flags ``METH_ARG0_FUNCTION`` and ``METH_ARG0_NO_SLICE``.
That is not a problem because ``METH_ARG0_FUNCTION`` already disables self slicing. That is not a problem because ``METH_ARG0_FUNCTION`` already disables self slicing.
@ -454,7 +461,7 @@ We add and change some Python/C API functions:
the old functions are kept as aliases of the new functions. the old functions are kept as aliases of the new functions.
**TODO**: more functions may be added when implementing this PEP. **TODO**: more functions may be added when implementing this PEP.
In particular, maybe there should be functions for creating instances of ``basefunction`` In particular, there should probably be functions for creating instances of ``basefunction``
or ``generic_function``. or ``generic_function``.
Changes to the types module Changes to the types module
@ -511,7 +518,7 @@ Non-CPython implementations
=========================== ===========================
For other implementations of Python apart from CPython, For other implementations of Python apart from CPython,
only the classes ``basefunction``, ``method`` and ``python_function`` are required. only the classes ``basefunction``, ``bound_method`` and ``python_function`` are required.
The latter two are the only classes which can be instantiated directly The latter two are the only classes which can be instantiated directly
from the Python interpreter. from the Python interpreter.
We require ``basefunction`` for consistency but we put no requirements on it: We require ``basefunction`` for consistency but we put no requirements on it:
@ -620,7 +627,7 @@ __self__ in basefunction
------------------------ ------------------------
It may look strange at first sight to add the ``__self__`` slot It may look strange at first sight to add the ``__self__`` slot
in ``basefunction`` as opposed to ``method``. in ``basefunction`` as opposed to ``bound_method``.
We took this idea from the existing ``builtin_function_or_method`` class. We took this idea from the existing ``builtin_function_or_method`` class.
It allows us to have a single general implementation of ``__call__`` It allows us to have a single general implementation of ``__call__``
for the various function classes discussed in this PEP. for the various function classes discussed in this PEP.
@ -630,7 +637,7 @@ which set ``__self__`` to the module (for example, ``sys.exit.__self__`` is ``sy
Subclassing Subclassing
----------- -----------
We disallow subclassing of ``builtin_function`` and ``method`` We disallow subclassing of ``builtin_function`` and ``bound_method``
to enable fast type checks for ``PyBuiltinFunction_Check`` and ``PyMethod_Check()``. to enable fast type checks for ``PyBuiltinFunction_Check`` and ``PyMethod_Check()``.
We allow subclassing of the other classes because there is no reason to disallow it. We allow subclassing of the other classes because there is no reason to disallow it.
@ -751,8 +758,8 @@ We expect that this will not cause problems.
Reference Implementation Reference Implementation
======================== ========================
After initial discussions of this PEP draft, The implementation in CPython is being developed at
work will start on a reference implementation in CPython. https://github.com/jdemeyer/cpython/tree/pep575
Appendix: current situation Appendix: current situation
@ -878,6 +885,8 @@ References
.. [#bpo30071] Python bug 30071 (https://bugs.python.org/issue30071) .. [#bpo30071] Python bug 30071 (https://bugs.python.org/issue30071)
.. [#ABI] PEP 384, Defining a Stable ABI, Löwis (https://www.python.org/dev/peps/pep-0384)
.. [#clinic] PEP 436, The Argument Clinic DSL, Hastings (https://www.python.org/dev/peps/pep-0436) .. [#clinic] PEP 436, The Argument Clinic DSL, Hastings (https://www.python.org/dev/peps/pep-0436)
.. [#methoddoc] PyMethodDef documentation (https://docs.python.org/3.7/c-api/structures.html#c.PyMethodDef) .. [#methoddoc] PyMethodDef documentation (https://docs.python.org/3.7/c-api/structures.html#c.PyMethodDef)