Update PEP 575 (#608)

This commit is contained in:
jdemeyer 2018-04-05 17:30:16 +02:00 committed by Chris Angelico
parent e79b63a128
commit f58b37ce8e
1 changed files with 57 additions and 50 deletions

View File

@ -84,15 +84,17 @@ It behaves like the existing ``builtin_function_or_method``
with some differences:
#. It acts as a descriptor implementing ``__get__`` to turn a function into a method
if there was no ``__self__`` attribute.
If the ``__self__`` attribute was already set, then this is a no-op:
the existing function is returned instead.
if ``m_self`` is ``NULL``.
If ``m_self`` is not ``NULL``,
then this is a no-op: the existing function is returned instead.
#. A new read-only slot ``__objclass__``, represented in the C structure as ``m_objclass``.
If this attribute exists, it must be an extension type.
If this attribute exists, it must be a 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``.
The pointer ``m_objclass`` is not considered a reference.
This is mainly meant to support unbound methods of extension types,
replacing ``method_descriptor``.
Also ``__qualname__`` will use ``__objclass__`` as namespace
(instead of ``__self__``).
#. Argument Clinic [#clinic]_ is not supported.
@ -107,10 +109,17 @@ with some differences:
equal to the function object instead of ``__self__``.
#. 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 and ``__self__`` is not set,
then the first positional argument is treated as ``__self__``.
For more details, see `Self slicing`_.
#. A new flag ``METH_BINDING`` for ``ml_flags`` which only applies to
functions of a module (not methods of a class).
If this flag is set, then ``m_self`` will be set to ``NULL`` instead
of the module.
This allows the function to behave more like a Python function
as it enables ``__get__``.
#. A new flag ``METH_PYTHON`` for ``ml_flags``.
This flag indicates that this function should be treated as Python function.
Ideally, use of this flag should be avoided because it goes
@ -257,16 +266,16 @@ It adds one new attribute on top of ``basefunction``:
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
may not be an instance of ``basefunction``.
constructing a method from an arbitrary callable.
This may be an already-bound method or simply not an instance of ``basefunction``.
Therefore, in practice there are two kinds of methods:
for arbitrary callables, we use a single fixed ``PyCFunctionDef``
structure with ``ml_name`` equal to ``"?"``
and with the ``METH_ARG0_FUNCTION`` flag set.
structure with the ``METH_ARG0_FUNCTION`` flag set.
The C function then calls ``__func__`` with the correct arguments.
For methods which bind instances of ``basefunction``
(more precisely, which have the ``Py_TPFLAGS_BASEFUNCTION`` flag set),
(more precisely, which have the ``Py_TPFLAGS_BASEFUNCTION`` flag set)
that have ``m_self == NULL``,
we instead use the ``PyCFunctionDef`` from the original function.
In this case, the ``__func__`` attribute is only used to implement various attributes
but not for calling the method.
@ -292,8 +301,8 @@ We specify the implementation of ``__call__`` for instances of ``basefunction``.
__objclass__
------------
First of all, if the function has an ``__objclass__`` attribute but no
``__self__`` attribute (this is the case for unbound methods of extension types),
First of all, if the function has an ``__objclass__`` attribute but
``m_self`` is ``NULL`` (this is the case for non-static unbound methods of extension types),
then the function must be called with at least one positional argument
and the first (typically called ``self``) must be an instance of ``__objclass__``.
If not, a ``TypeError`` is raised.
@ -321,9 +330,9 @@ We explain the others shortly.
Self slicing
------------
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__``)
If the function has no ``__self__``
attribute and none of the flags ``METH_ARG0_FUNCTION``, ``METH_ARG0_NO_SLICE`` nor ``METH_STATIC`` is set,
then the first positional argument (if any)
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".
@ -395,7 +404,7 @@ Built-in functions of a module
------------------------------
For the case of functions of a module,
``__self__`` will be set to the module unless the flag ``METH_STATIC`` is set.
``__self__`` will be set to the module unless the flag ``METH_BINDING`` is set.
An important consequence is that such functions by default
do not become methods when used as attribute
@ -405,9 +414,7 @@ in an initial post on python-ideas [#proposal]_ the concensus was to keep this
misfeature of built-in functions.
However, to allow this anyway for specific or newly implemented
built-in functions, the ``METH_STATIC`` flag prevents setting ``__self__``.
Previously, ``METH_STATIC`` was an error, so this is fullt backwards compatible.
Specifying ``METH_CLASS`` is still an error.
built-in functions, the ``METH_BINDING`` flag prevents setting ``__self__``.
Further changes
@ -439,12 +446,19 @@ We add and change some Python/C API functions:
- ``int PyBaseFunction_Check(PyObject *op)``: return true if ``op``
is an instance of a type with the ``Py_TPFLAGS_BASEFUNCTION`` set.
- ``int PyCFunction_Check(PyObject *op)``: return true if ``PyBaseFunction_Check(op)``
is True and the function ``op`` does not have the flag ``METH_PYTHON`` set.
- ``PyObject* PyBaseFunction_New(PyTypeObject *cls, PyCFunctionDef *ml, PyObject *self, PyObject *module, PyTypeObject *objclass)``:
create a new instance of ``cls`` (which must be a subclass of ``basefunction``)
from the given data.
- ``int PyBuiltinFunction_Check(PyObject *op)``: return true if ``op``
- ``int PyCFunction_Check(PyObject *op)``: return true if ``op``
is an instance of ``builtin_function``.
- ``int PyCFunction_NewEx(PyMethodDef* ml, PyObject *self, PyObject* module)``:
create a new instance of ``builtin_function``.
As special case, if ``self`` is ``NULL``,
then set ``self = Py_None`` instead.
This is done for backwards compatibility.
- ``int PyFunction_Check(PyObject *op)``: return true if ``op``
is an instance of ``generic_function``.
@ -460,10 +474,6 @@ We add and change some Python/C API functions:
For backwards compatibility,
the old functions are kept as aliases of the new functions.
**TODO**: more functions may be added when implementing this PEP.
In particular, there should probably be functions for creating instances of ``basefunction``
or ``generic_function``.
Changes to the types module
---------------------------
@ -659,36 +669,33 @@ of ``PyBaseFunctionObject.m_ml.ml_meth`` with flags
``METH_VARARGS | METH_KEYWORDS | METH_ARG0_FUNCTION``.
Therefore, it should be easy to change existing ``tp_call`` slots
to use ``METH_ARG0_FUNCTION``.
There is just one extra complication: ``__self__`` must be handled manually.
That is not hard though: it just means adapting that logic from ``method``.
There is one extra complication though: ``__self__`` must be handled manually.
Self slicing: METH_ARG0_NO_SLICE
--------------------------------
We define "self slicing" to mean slicing off the ``self`` argument of a method
from the ``*args`` tuple when an unbound method is called.
This ``self`` argument is then passed as first argument to the C function.
**TODO**: ``METH_ARG0_NO_SLICE`` will probably be dropped from
the PEP since both ``METH_ARG0_FUNCTION`` and ``METH_STATIC``
already disable self slicing.
The specification of ``METH_ARG0_NO_SLICE`` may seem strange at first.
The negation is confusing, but it is done for backwards compatibility:
existing methods require self slicing but do not specify a flag for it.
.. We define "self slicing" to mean slicing off the ``self`` argument of a method
from the ``*args`` tuple when an unbound method is called.
This ``self`` argument is then passed as first argument to the C function.
The requirement for ``__objclass__`` in order to use self slicing
makes sense because it guarantees that there is a ``self`` argument in the first place.
.. The specification of ``METH_ARG0_NO_SLICE`` may seem strange at first.
The negation is confusing, but it is done for backwards compatibility:
existing methods require self slicing but do not specify a flag for it.
Since ``METH_ARG0_FUNCTION`` is clearly incompatible with self slicing
(both use the first argument of the C function),
this PEP dictates that ``METH_ARG0_FUNCTION`` disables self slicing.
So one may wonder if there is actually a use case for ``METH_ARG0_NO_SLICE``
without ``METH_ARG0_FUNCTION``.
If not, then one could simply unify those two flags in one flag
``METH_ARG0_FUNCTION``.
.. Since ``METH_ARG0_FUNCTION`` is clearly incompatible with self slicing
(both use the first argument of the C function),
this PEP dictates that ``METH_ARG0_FUNCTION`` disables self slicing.
So one may wonder if there is actually a use case for ``METH_ARG0_NO_SLICE``
without ``METH_ARG0_FUNCTION``.
If not, then one could simply unify those two flags in one flag
``METH_ARG0_FUNCTION``.
However, a priori, the flag ``METH_ARG0_NO_SLICE`` is meaningful,
so we keep the two flags ``METH_ARG0_FUNCTION`` and ``METH_ARG0_NO_SLICE`` separate.
**TODO**: this should be reconsidered after initial implementation
and testing of this PEP.
.. However, a priori, the flag ``METH_ARG0_NO_SLICE`` is meaningful,
so we keep the two flags ``METH_ARG0_FUNCTION`` and ``METH_ARG0_NO_SLICE`` separate.
User flags: METH_CUSTOM and METH_USRx
-------------------------------------