Improve readability
This commit is contained in:
parent
970e9c5346
commit
49a5c29d8f
86
pep-0487.txt
86
pep-0487.txt
|
@ -232,16 +232,50 @@ PEP::
|
|||
Implementation Details
|
||||
======================
|
||||
|
||||
For those who prefer reading Python over english, the following is a Python
|
||||
equivalent of the C API changes proposed in this PEP, where the new ``object``
|
||||
and ``type`` defined here inherit from the usual ones::
|
||||
The different hooks are called in the following order: ``type.__new__`` calls
|
||||
the ``__set_name__`` hooks on the descriptor after the new class has been
|
||||
initialized. Then it calls ``__init_subclass__`` on the base class, on
|
||||
``super()``, to be precise. This means that subclass initializers already
|
||||
see the fully initialized descriptors. This way, ``__init_subclass__`` users
|
||||
can fix all descriptors again if this is needed.
|
||||
|
||||
import types
|
||||
Another option would have been to call ``__set_name__`` in the base
|
||||
implementation of ``object.__init_subclass__``. This way it would be possible
|
||||
even to prevent ``__set_name__`` from being called. Most of the times,
|
||||
however, such a prevention would be accidental, as it often happens that a call
|
||||
to ``super()`` is forgotten.
|
||||
|
||||
class type(type):
|
||||
Another small change should be done: in the current implementation of
|
||||
CPython, ``type.__init__`` explicitly forbids the use of keyword arguments,
|
||||
while ``type.__new__`` allows for its attributes to be shipped as keyword
|
||||
arguments. This is weirdly incoherent, and thus it should be forbidden.
|
||||
While it would be possible to retain the current behavior, it would be better
|
||||
if this was fixed, as it is probably not used at all: the only use case would
|
||||
be that at metaclass calls its ``super().__new__`` with *name*, *bases* and
|
||||
*dict* (yes, *dict*, not *namespace* or *ns* as mostly used with modern
|
||||
metaclasses) as keyword arguments. This should not be done. This little
|
||||
change simplifies the implementation of this PEP significantly, while
|
||||
improving the coherence of Python overall.
|
||||
|
||||
As a second change, the new ``type.__init__`` just ignores keyword
|
||||
arguments. Currently, it insists that no keyword arguments are given. This
|
||||
leads to a (wanted) error if one gives keyword arguments to a class declaration
|
||||
if the metaclass does not process them. Metaclass authors that do want to
|
||||
accept keyword arguments must filter them out by overriding ``__init___``.
|
||||
|
||||
In the new code, it is not ``__init__`` that complains about keyword arguments,
|
||||
but ``__init_subclass__``, whose default implementation takes no arguments. In
|
||||
a classical inheritance scheme using the method resolution order, each
|
||||
``__init_subclass__`` may take out it's keyword arguments until none are left,
|
||||
which is checked by the default implementation of ``__init_subclass__``.
|
||||
|
||||
For readers who prefer reading Python over English, this PEP proposes to
|
||||
replace the current ``type`` and ``object`` with the following::
|
||||
|
||||
class NewType(type):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if len(args) == 1:
|
||||
return super().__new__(cls, args[0])
|
||||
if len(args) != 3:
|
||||
return super().__new__(cls, *args)
|
||||
name, bases, ns = args
|
||||
init = ns.get('__init_subclass__')
|
||||
if isinstance(init, types.FunctionType):
|
||||
|
@ -257,47 +291,11 @@ and ``type`` defined here inherit from the usual ones::
|
|||
def __init__(self, name, bases, ns, **kwargs):
|
||||
super().__init__(name, bases, ns)
|
||||
|
||||
class object:
|
||||
class NewObject(object):
|
||||
@classmethod
|
||||
def __init_subclass__(cls):
|
||||
pass
|
||||
|
||||
class object(object, metaclass=type):
|
||||
pass
|
||||
|
||||
In this code, first the ``__set_name__`` are called on the descriptors, and
|
||||
then the ``__init_subclass__``. This means that subclass initializers already
|
||||
see the fully initialized descriptors. This way, ``__init_subclass__`` users
|
||||
can fix all descriptors again if this is needed.
|
||||
|
||||
Another option would have been to call ``__set_name__`` in the base
|
||||
implementation of ``object.__init_subclass__``. This way it would be possible
|
||||
even to prevent ``__set_name__`` from being called. Most of the times,
|
||||
however, such a prevention would be accidental, as it often happens that a call
|
||||
to ``super()`` is forgotten.
|
||||
|
||||
Another small change should be noted here: in the current implementation of
|
||||
CPython, ``type.__init__`` explicitly forbids the use of keyword arguments,
|
||||
while ``type.__new__`` allows for its attributes to be shipped as keyword
|
||||
arguments. This is weirdly incoherent, and thus the above code forbids that.
|
||||
While it would be possible to retain the current behavior, it would be better
|
||||
if this was fixed, as it is probably not used at all: the only use case would
|
||||
be that at metaclass calls its ``super().__new__`` with *name*, *bases* and
|
||||
*dict* (yes, *dict*, not *namespace* or *ns* as mostly used with modern
|
||||
metaclasses) as keyword arguments. This should not be done.
|
||||
|
||||
As a second change, the new ``type.__init__`` just ignores keyword
|
||||
arguments. Currently, it insists that no keyword arguments are given. This
|
||||
leads to a (wanted) error if one gives keyword arguments to a class declaration
|
||||
if the metaclass does not process them. Metaclass authors that do want to
|
||||
accept keyword arguments must filter them out by overriding ``__init___``.
|
||||
|
||||
In the new code, it is not ``__init__`` that complains about keyword arguments,
|
||||
but ``__init_subclass__``, whose default implementation takes no arguments. In
|
||||
a classical inheritance scheme using the method resolution order, each
|
||||
``__init_subclass__`` may take out it's keyword arguments until none are left,
|
||||
which is checked by the default implementation of ``__init_subclass__``.
|
||||
|
||||
|
||||
Rejected Design Options
|
||||
=======================
|
||||
|
|
Loading…
Reference in New Issue