Update PEP 575 (#608)
This commit is contained in:
parent
e79b63a128
commit
f58b37ce8e
87
pep-0575.rst
87
pep-0575.rst
|
@ -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,24 +669,24 @@ 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
|
||||
**TODO**: ``METH_ARG0_NO_SLICE`` will probably be dropped from
|
||||
the PEP since both ``METH_ARG0_FUNCTION`` and ``METH_STATIC``
|
||||
already disable self slicing.
|
||||
|
||||
.. 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 specification of ``METH_ARG0_NO_SLICE`` may seem strange at first.
|
||||
.. 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.
|
||||
|
||||
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.
|
||||
|
||||
Since ``METH_ARG0_FUNCTION`` is clearly incompatible with self slicing
|
||||
.. 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``
|
||||
|
@ -684,12 +694,9 @@ 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,
|
||||
.. 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.
|
||||
|
||||
User flags: METH_CUSTOM and METH_USRx
|
||||
-------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue