Add Daniel as PEP 422 co-author, misc fixes
This commit is contained in:
parent
a7dc8cb417
commit
9a660dde6b
37
pep-0422.txt
37
pep-0422.txt
|
@ -2,7 +2,8 @@ PEP: 422
|
|||
Title: Simple class initialisation hook
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Nick Coghlan <ncoghlan@gmail.com>
|
||||
Author: Nick Coghlan <ncoghlan@gmail.com>,
|
||||
Daniel Urban <urban.dani+py@gmail.com>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
|
@ -19,7 +20,7 @@ was created (or simply arrange to run other code after the class was created)
|
|||
by setting the ``__metaclass__`` attribute in the class body. While doing
|
||||
this implicitly from called code required the use of an implementation detail
|
||||
(specifically, ``sys._getframes()``), it could also be done explicitly in a
|
||||
fully supported fashion (for example, by passing ``locals()`` to an
|
||||
fully supported fashion (for example, by passing ``locals()`` to a
|
||||
function that calculated a suitable ``__metaclass__`` value)
|
||||
|
||||
There is currently no corresponding mechanism in Python 3 that allows the
|
||||
|
@ -44,7 +45,7 @@ the metaclass hint that may be provided as part of the class definition.
|
|||
While in many cases these two meanings end up referring to one and the same
|
||||
object, there are two situations where that is not the case:
|
||||
|
||||
* If the metaclass hint refers to a subclass of ``type``, then it is
|
||||
* If the metaclass hint refers to an instance of ``type``, then it is
|
||||
considered as a candidate metaclass along with the metaclasses of all of
|
||||
the parents of the class being defined. If a more appropriate metaclass is
|
||||
found amongst the candidates, then it will be used instead of the one
|
||||
|
@ -114,7 +115,7 @@ class initialisation hook as follows::
|
|||
# This is invoked after the class is created, but before any
|
||||
# explicit decorators are called
|
||||
# The usual super() mechanisms are used to correctly support
|
||||
# multiple inheritance. The decorator style invocation helps
|
||||
# multiple inheritance. The class decorator style signature helps
|
||||
# ensure that invoking the parent class is as simple as possible.
|
||||
|
||||
If present on the created object, this new hook will be called by the class
|
||||
|
@ -125,10 +126,17 @@ returning the created class object.
|
|||
If a metaclass wishes to block class initialisation for some reason, it
|
||||
must arrange for ``cls.__init_class__`` to trigger ``AttributeError``.
|
||||
|
||||
Note, that when ``__init_class__`` is called, the name of the class is not
|
||||
bound to the new class object yet. 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
|
||||
``super()`` works as expected, since the ``__class__`` reference is already
|
||||
initialised.
|
||||
|
||||
This general proposal is not a new idea (it was first suggested for
|
||||
inclusion in the language definition `more than 10 years ago`_, and a
|
||||
similar mechanism has long been supported by `Zope's ExtensionClass`_),
|
||||
but I believe the situation has changed sufficiently in recent years that
|
||||
but the situation has changed sufficiently in recent years that
|
||||
the idea is worth reconsidering.
|
||||
|
||||
|
||||
|
@ -156,7 +164,7 @@ the metaclass hint, the actual metaclass, the class object, instances of the
|
|||
class object) clearly distinct in your mind. Even when you know the rules,
|
||||
it's still easy to make a mistake if you're not being extremely careful.
|
||||
An earlier version of this PEP actually included such a mistake: it
|
||||
stated "instance of type" for a constraint that is actually "subclass of
|
||||
stated "subclass of type" for a constraint that is actually "instance of
|
||||
type".
|
||||
|
||||
Understanding the proposed class initialisation hook only requires
|
||||
|
@ -278,17 +286,24 @@ iterable ``__decorators__`` attributes.
|
|||
Using the current version of the PEP, the scheme originally proposed could
|
||||
be implemented as::
|
||||
|
||||
class DynamicDecorators:
|
||||
class DynamicDecorators(Base):
|
||||
@classmethod
|
||||
def __init_class__(cls):
|
||||
super(DynamicDecorators, cls).__init_class__()
|
||||
# Process any classes later in the MRO
|
||||
try:
|
||||
mro_chain = super().__init_class__
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
mro_chain()
|
||||
# Process any __decorators__ attributes in the MRO
|
||||
for entry in reversed(cls.mro()):
|
||||
decorators = entry.__dict__.get("__decorators__", ())
|
||||
for deco in reversed(decorators):
|
||||
cls = deco(cls)
|
||||
|
||||
Any subclasses of this type would automatically have the contents of any
|
||||
``__decorators__`` attributes processed and invoked.
|
||||
Any subclasses of ``DynamicDecorators`` would then automatically have the
|
||||
contents of any ``__decorators__`` attributes processed and invoked.
|
||||
|
||||
The mechanism in the current PEP is considered superior, as many issues
|
||||
to do with ordering and the same decorator being invoked multiple times
|
||||
|
@ -328,7 +343,7 @@ relied on the ``__class__`` reference (or used the zero-argument form of
|
|||
Reference Implementation
|
||||
========================
|
||||
|
||||
Daniel Urban has posted a reference implementation to the `issue tracker`_.
|
||||
The reference implementation has been posted to the `issue tracker`_.
|
||||
|
||||
|
||||
References
|
||||
|
|
Loading…
Reference in New Issue