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:
|
with some differences:
|
||||||
|
|
||||||
#. It acts as a descriptor implementing ``__get__`` to turn a function into a method
|
#. It acts as a descriptor implementing ``__get__`` to turn a function into a method
|
||||||
if there was no ``__self__`` attribute.
|
if ``m_self`` is ``NULL``.
|
||||||
If the ``__self__`` attribute was already set, then this is a no-op:
|
If ``m_self`` is not ``NULL``,
|
||||||
the existing function is returned instead.
|
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``.
|
#. 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.
|
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 mainly meant to support unbound methods of extension types,
|
||||||
The pointer ``m_objclass`` is not considered a reference.
|
replacing ``method_descriptor``.
|
||||||
|
Also ``__qualname__`` will use ``__objclass__`` as namespace
|
||||||
|
(instead of ``__self__``).
|
||||||
|
|
||||||
#. Argument Clinic [#clinic]_ is not supported.
|
#. Argument Clinic [#clinic]_ is not supported.
|
||||||
|
|
||||||
|
@ -107,10 +109,17 @@ with some differences:
|
||||||
equal to the function object instead of ``__self__``.
|
equal to the function object instead of ``__self__``.
|
||||||
|
|
||||||
#. 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 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 `Self slicing`_.
|
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``.
|
#. 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.
|
||||||
Ideally, use of this flag should be avoided because it goes
|
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.
|
which was used only for Python functions bound as method.
|
||||||
|
|
||||||
There is a complication because we want to allow
|
There is a complication because we want to allow
|
||||||
constructing a method from a arbitrary callable which
|
constructing a method from an arbitrary callable.
|
||||||
may not be an instance of ``basefunction``.
|
This may be an already-bound method or simply not an instance of ``basefunction``.
|
||||||
Therefore, in practice there are two kinds of methods:
|
Therefore, in practice there are two kinds of methods:
|
||||||
for arbitrary callables, we use a single fixed ``PyCFunctionDef``
|
for arbitrary callables, we use a single fixed ``PyCFunctionDef``
|
||||||
structure with ``ml_name`` equal to ``"?"``
|
structure with the ``METH_ARG0_FUNCTION`` flag set.
|
||||||
and with the ``METH_ARG0_FUNCTION`` flag set.
|
|
||||||
The C function then calls ``__func__`` with the correct arguments.
|
The C function then calls ``__func__`` with the correct arguments.
|
||||||
|
|
||||||
For methods which bind instances of ``basefunction``
|
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.
|
we instead use the ``PyCFunctionDef`` from the original function.
|
||||||
In this case, the ``__func__`` attribute is only used to implement various attributes
|
In this case, the ``__func__`` attribute is only used to implement various attributes
|
||||||
but not for calling the method.
|
but not for calling the method.
|
||||||
|
@ -292,8 +301,8 @@ We specify the implementation of ``__call__`` for instances of ``basefunction``.
|
||||||
__objclass__
|
__objclass__
|
||||||
------------
|
------------
|
||||||
|
|
||||||
First of all, if the function has an ``__objclass__`` attribute but no
|
First of all, if the function has an ``__objclass__`` attribute but
|
||||||
``__self__`` attribute (this is the case for unbound methods of extension types),
|
``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
|
then the function must be called with at least one positional argument
|
||||||
and the first (typically called ``self``) must be an instance of ``__objclass__``.
|
and the first (typically called ``self``) must be an instance of ``__objclass__``.
|
||||||
If not, a ``TypeError`` is raised.
|
If not, a ``TypeError`` is raised.
|
||||||
|
@ -321,9 +330,9 @@ We explain the others shortly.
|
||||||
Self slicing
|
Self slicing
|
||||||
------------
|
------------
|
||||||
|
|
||||||
If the function has a ``__objclass__`` attribute, no ``__self__``
|
If the function has no ``__self__``
|
||||||
attribute and neither ``METH_ARG0_FUNCTION`` nor ``METH_ARG0_NO_SLICE`` is set,
|
attribute and none of the flags ``METH_ARG0_FUNCTION``, ``METH_ARG0_NO_SLICE`` nor ``METH_STATIC`` is set,
|
||||||
then the first positional argument (which must exist because of ``__objclass__``)
|
then the first positional argument (if any)
|
||||||
is removed from ``*args`` and instead passed as first argument to the C function.
|
is removed from ``*args`` and instead passed as first argument to the C function.
|
||||||
Effectively, the first positional argument is treated as ``__self__``.
|
Effectively, the first positional argument is treated as ``__self__``.
|
||||||
This process is called "self slicing".
|
This process is called "self slicing".
|
||||||
|
@ -395,7 +404,7 @@ Built-in functions of a module
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
For the case of 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
|
An important consequence is that such functions by default
|
||||||
do not become methods when used as attribute
|
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.
|
misfeature of built-in functions.
|
||||||
|
|
||||||
However, to allow this anyway for specific or newly implemented
|
However, to allow this anyway for specific or newly implemented
|
||||||
built-in functions, the ``METH_STATIC`` flag prevents setting ``__self__``.
|
built-in functions, the ``METH_BINDING`` flag prevents setting ``__self__``.
|
||||||
Previously, ``METH_STATIC`` was an error, so this is fullt backwards compatible.
|
|
||||||
Specifying ``METH_CLASS`` is still an error.
|
|
||||||
|
|
||||||
|
|
||||||
Further changes
|
Further changes
|
||||||
|
@ -439,12 +446,19 @@ We add and change some Python/C API functions:
|
||||||
- ``int PyBaseFunction_Check(PyObject *op)``: return true if ``op``
|
- ``int PyBaseFunction_Check(PyObject *op)``: return true if ``op``
|
||||||
is an instance of a type with the ``Py_TPFLAGS_BASEFUNCTION`` set.
|
is an instance of a type with the ``Py_TPFLAGS_BASEFUNCTION`` set.
|
||||||
|
|
||||||
- ``int PyCFunction_Check(PyObject *op)``: return true if ``PyBaseFunction_Check(op)``
|
- ``PyObject* PyBaseFunction_New(PyTypeObject *cls, PyCFunctionDef *ml, PyObject *self, PyObject *module, PyTypeObject *objclass)``:
|
||||||
is True and the function ``op`` does not have the flag ``METH_PYTHON`` set.
|
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``.
|
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``
|
- ``int PyFunction_Check(PyObject *op)``: return true if ``op``
|
||||||
is an instance of ``generic_function``.
|
is an instance of ``generic_function``.
|
||||||
|
|
||||||
|
@ -460,10 +474,6 @@ We add and change some Python/C API functions:
|
||||||
For backwards compatibility,
|
For backwards compatibility,
|
||||||
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.
|
|
||||||
In particular, there should probably be functions for creating instances of ``basefunction``
|
|
||||||
or ``generic_function``.
|
|
||||||
|
|
||||||
Changes to the types module
|
Changes to the types module
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
@ -659,24 +669,24 @@ of ``PyBaseFunctionObject.m_ml.ml_meth`` with flags
|
||||||
``METH_VARARGS | METH_KEYWORDS | METH_ARG0_FUNCTION``.
|
``METH_VARARGS | METH_KEYWORDS | METH_ARG0_FUNCTION``.
|
||||||
Therefore, it should be easy to change existing ``tp_call`` slots
|
Therefore, it should be easy to change existing ``tp_call`` slots
|
||||||
to use ``METH_ARG0_FUNCTION``.
|
to use ``METH_ARG0_FUNCTION``.
|
||||||
There is just one extra complication: ``__self__`` must be handled manually.
|
There is one extra complication though: ``__self__`` must be handled manually.
|
||||||
That is not hard though: it just means adapting that logic from ``method``.
|
|
||||||
|
|
||||||
Self slicing: METH_ARG0_NO_SLICE
|
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.
|
from the ``*args`` tuple when an unbound method is called.
|
||||||
This ``self`` argument is then passed as first argument to the C function.
|
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:
|
The negation is confusing, but it is done for backwards compatibility:
|
||||||
existing methods require self slicing but do not specify a flag for it.
|
existing methods require self slicing but do not specify a flag for it.
|
||||||
|
|
||||||
The requirement for ``__objclass__`` in order to use self slicing
|
.. Since ``METH_ARG0_FUNCTION`` is clearly incompatible with 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
|
|
||||||
(both use the first argument of the C function),
|
(both use the first argument of the C function),
|
||||||
this PEP dictates that ``METH_ARG0_FUNCTION`` disables self slicing.
|
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``
|
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
|
If not, then one could simply unify those two flags in one flag
|
||||||
``METH_ARG0_FUNCTION``.
|
``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.
|
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
|
User flags: METH_CUSTOM and METH_USRx
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue