Add Daniel as PEP 422 co-author, misc fixes

This commit is contained in:
Nick Coghlan 2013-02-10 22:13:58 +10:00
parent a7dc8cb417
commit 9a660dde6b
1 changed files with 26 additions and 11 deletions

View File

@ -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