PEP 422: Rename init_class as autodecorate
This commit is contained in:
parent
d50818e4e8
commit
a9817b6218
88
pep-0422.txt
88
pep-0422.txt
|
@ -21,9 +21,9 @@ creating the potential for spurious metaclass conflicts.
|
|||
|
||||
This PEP proposes to instead support a wide range of customisation
|
||||
scenarios through a new ``namespace`` parameter in the class header, and
|
||||
a new ``__init_class__`` hook in the class body.
|
||||
a new ``__autodecorate__`` hook in the class body.
|
||||
|
||||
The new mechanism is also much easier to understand and use than
|
||||
The new mechanism should be easier to understand and use than
|
||||
implementing a custom metaclass, and thus should provide a gentler
|
||||
introduction to the full power Python's metaclass machinery.
|
||||
|
||||
|
@ -109,16 +109,16 @@ added to Python 3.4 that meets the following criteria:
|
|||
but potentially without the full flexibility of the Python 2 style
|
||||
``__metaclass__`` hook
|
||||
|
||||
One mechanism that can achieve this goal is to add a new class
|
||||
initialisation hook, modelled directly on the existing instance
|
||||
initialisation hook, but with the signature constrained to match that
|
||||
of an ordinary class decorator.
|
||||
One mechanism that can achieve this goal is to add a new implicit class
|
||||
decoration hook, modelled directly on the existing explicit class
|
||||
decorators, but defined in the class body or in a parent class, rather than
|
||||
being part of the class definition header.
|
||||
|
||||
Specifically, it is proposed that class definitions be able to provide a
|
||||
class initialisation hook as follows::
|
||||
|
||||
class Example:
|
||||
def __init_class__(cls):
|
||||
def __autodecorate__(cls):
|
||||
# This is invoked after the class is created, but before any
|
||||
# explicit decorators are called
|
||||
# The usual super() mechanisms are used to correctly support
|
||||
|
@ -128,14 +128,14 @@ class initialisation hook as follows::
|
|||
If present on the created object, this new hook will be called by the class
|
||||
creation machinery *after* the ``__class__`` reference has been initialised.
|
||||
For ``types.new_class()``, it will be called as the last step before
|
||||
returning the created class object. ``__init_class__`` is implicitly
|
||||
returning the created class object. ``__autodecorate__`` is implicitly
|
||||
converted to a class method when the class is created (prior to the hook
|
||||
being invoked).
|
||||
|
||||
If a metaclass wishes to block class initialisation for some reason, it
|
||||
must arrange for ``cls.__init_class__`` to trigger ``AttributeError``.
|
||||
If a metaclass wishes to block implicit class decoration for some reason, it
|
||||
must arrange for ``cls.__autodecorate__`` to trigger ``AttributeError``.
|
||||
|
||||
Note, that when ``__init_class__`` is called, the name of the class is not
|
||||
Note, that when ``__autodecorate__`` is called, the name of the class is not
|
||||
yet bound to the new class object. As a consequence, the two argument form
|
||||
of ``super()`` cannot be used to call methods (e.g., ``super(Example, cls)``
|
||||
wouldn't work in the example above). However, the zero argument form of
|
||||
|
@ -158,7 +158,7 @@ created dictionary instance. For example, the following will use
|
|||
an ordered dictionary as the class namespace::
|
||||
|
||||
class OrderedExample(namespace=collections.OrderedDict):
|
||||
def __init_class__(cls):
|
||||
def __autodecorate__(cls):
|
||||
# cls.__dict__ is still a read-only proxy to the class namespace,
|
||||
# but the underlying storage is an OrderedDict instance
|
||||
|
||||
|
@ -220,12 +220,12 @@ These occur whenever two unrelated metaclasses are used by the desired
|
|||
parents of a class definition. This risk also makes it very difficult to
|
||||
*add* a metaclass to a class that has previously been published without one.
|
||||
|
||||
By contrast, adding an ``__init_class__`` method to an existing type poses
|
||||
By contrast, adding an ``__autodecorate__`` method to an existing type poses
|
||||
a similar level of risk to adding an ``__init__`` method: technically, there
|
||||
is a risk of breaking poorly implemented subclasses, but when that occurs,
|
||||
it is recognised as a bug in the subclass rather than the library author
|
||||
breaching backwards compatibility guarantees. In fact, due to the constrained
|
||||
signature of ``__init_class__``, the risk in this case is actually even
|
||||
signature of ``__autodecorate__``, the risk in this case is actually even
|
||||
lower than in the case of ``__init__``.
|
||||
|
||||
|
||||
|
@ -243,11 +243,33 @@ Replaces many use cases for dynamic setting of ``__metaclass__``
|
|||
|
||||
For use cases that don't involve completely replacing the defined class,
|
||||
Python 2 code that dynamically set ``__metaclass__`` can now dynamically
|
||||
set ``__init_class__`` instead. For more advanced use cases, introduction of
|
||||
set ``__autodecorate__`` instead. For more advanced use cases, introduction of
|
||||
an explicit metaclass (possibly made available as a required base class) will
|
||||
still be necessary in order to support Python 3.
|
||||
|
||||
|
||||
Design Notes
|
||||
============
|
||||
|
||||
|
||||
Determining if the class being decorated is the base class
|
||||
----------------------------------------------------------
|
||||
|
||||
In the body of an ``__autodecorate__`` method, as in any other class method,
|
||||
``__class__`` will be bound to the class declaring the method, while the
|
||||
value passed in may be a subclass.
|
||||
|
||||
This makes it relatively straightforward to skip processing the base class
|
||||
if necessary::
|
||||
|
||||
class Example:
|
||||
def __autodecorate__(cls):
|
||||
# Don't process the base class
|
||||
if cls is __class__:
|
||||
return
|
||||
# Process subclasses here
|
||||
|
||||
|
||||
New Ways of Using Classes
|
||||
=========================
|
||||
|
||||
|
@ -354,21 +376,39 @@ Rejected Design Options
|
|||
=======================
|
||||
|
||||
|
||||
Calling ``__init_class__`` from ``type.__init__``
|
||||
-------------------------------------------------
|
||||
Calling ``__autodecorate__`` from ``type.__init__``
|
||||
---------------------------------------------------
|
||||
|
||||
Calling the new hook automatically from ``type.__init__``, would achieve most
|
||||
of the goals of this PEP. However, using that approach would mean that
|
||||
``__init_class__`` implementations would be unable to call any methods that
|
||||
``__autodecorate__`` implementations would be unable to call any methods that
|
||||
relied on the ``__class__`` reference (or used the zero-argument form of
|
||||
``super()``), and could not make use of those features themselves.
|
||||
|
||||
|
||||
Requiring an explict decorator on ``__init_class__``
|
||||
----------------------------------------------------
|
||||
Calling the automatic decoration hook ``__init_class__``
|
||||
--------------------------------------------------------
|
||||
|
||||
Earlier versions of the PEP used the name ``__init_class__`` for the name
|
||||
of the new hook. There were three significant problems with this name:
|
||||
|
||||
* it was hard to remember if the correct spelling was ``__init_class__`` or
|
||||
``__class_init__``
|
||||
* the use of "init" in the name suggested the signature should match that
|
||||
of ``type.__init__``, which is not the case
|
||||
* the use of "init" in the name suggested the method would be run as part
|
||||
of class construction, which is not the case
|
||||
|
||||
The new name ``__autodecorate__`` was chosen to make it clear that the new
|
||||
initialisation hook is most usefully thought of as an implicitly invoked
|
||||
class decorator, rather than as being like an ``__init__`` method.
|
||||
|
||||
|
||||
Requiring an explicit decorator on ``__autodecorate__``
|
||||
-------------------------------------------------------
|
||||
|
||||
Originally, this PEP required the explicit use of ``@classmethod`` on the
|
||||
``__init_class__`` decorator. It was made implicit since there's no
|
||||
``__autodecorate__`` decorator. It was made implicit since there's no
|
||||
sensible interpretation for leaving it out, and that case would need to be
|
||||
detected anyway in order to give a useful error message.
|
||||
|
||||
|
@ -393,9 +433,9 @@ the factory function version.
|
|||
Reference Implementation
|
||||
========================
|
||||
|
||||
A reference implementation for __init_class__ has been posted to the
|
||||
`issue tracker`_. It does not yet include the new ``namespace`` parameter
|
||||
for ``type.__prepare__``.
|
||||
A reference implementation for ``__autodecorate__`` has been posted to the
|
||||
`issue tracker`_. It uses the original ``__init_class__`` naming and does
|
||||
not yet include the new ``namespace`` parameter for ``type.__prepare__``.
|
||||
|
||||
TODO
|
||||
====
|
||||
|
|
Loading…
Reference in New Issue