[Python-checkins] peps: PEP 422: Make __autodecorate__ a true decorator

nick.coghlan python-checkins at python.org
Mon Feb 23 12:34:46 CET 2015


https://hg.python.org/peps/rev/922b91d5b23d
changeset:   5704:922b91d5b23d
user:        Nick Coghlan <ncoghlan at gmail.com>
date:        Mon Feb 23 21:34:36 2015 +1000
summary:
  PEP 422: Make __autodecorate__ a true decorator

* __autodecorate__ is now defined as a true decorator that can
  replace the class object entirely
* question whether the namespace parameter is sufficiently
  valuable to be worth the extra complexity, or if Eric Snow's
  idea of using an ordered dict by default would suffice

files:
  pep-0422.txt |  96 +++++++++++++++++++++++++++++++++++++--
  1 files changed, 90 insertions(+), 6 deletions(-)


diff --git a/pep-0422.txt b/pep-0422.txt
--- a/pep-0422.txt
+++ b/pep-0422.txt
@@ -129,6 +129,18 @@
            # The usual super() mechanisms are used to correctly support
            # multiple inheritance. The class decorator style signature helps
            # ensure that invoking the parent class is as simple as possible.
+           cls = super().__autodecorate__()
+           return cls
+
+To simplify the cooperative multiple inheritance case, ``object`` will gain
+a default implementation of the hook that returns the class unmodified:
+
+   class object:
+       def __autodecorate__(cls):
+           return cls
+
+If a metaclass wishes to block implicit class decoration for some reason, it
+must arrange for ``cls.__autodecorate__`` to trigger ``AttributeError``.
 
 If present on the created object, this new hook will be called by the class
 creation machinery *after* the ``__class__`` reference has been initialised.
@@ -137,9 +149,6 @@
 converted to a class method when the class is created (prior to the hook
 being invoked).
 
-If a metaclass wishes to block implicit class decoration for some reason, it
-must arrange for ``cls.__autodecorate__`` to trigger ``AttributeError``.
-
 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)``
@@ -151,7 +160,7 @@
 inclusion in the language definition `more than 10 years ago`_, and a
 similar mechanism has long been supported by `Zope's ExtensionClass`_),
 but the situation has changed sufficiently in recent years that
-the idea is worth reconsidering.
+the idea is worth reconsidering for inclusion as a native language feature.
 
 In addition, the introduction of the metaclass ``__prepare__`` method in PEP
 3115 allows a further enhancement that was not possible in Python 2: this
@@ -269,6 +278,7 @@
 
    class Example:
        def __autodecorate__(cls):
+           cls = super().__autodecorate__()
            # Don't process the base class
            if cls is __class__:
                return
@@ -276,6 +286,58 @@
            ...
 
 
+Replacing a class with a different kind of object
+-------------------------------------------------
+
+As an implicit decorator, ``__autodecorate__`` is able to relatively easily
+replace the defined class with a different kind of object. Technically
+custom metaclasses and even ``__new__`` methods can already do this
+implicitly, but the decorator model makes such code much easier to understand
+and implement.
+
+   class BuildDict:
+       def __autodecorate__(cls):
+           cls = super().__autodecorate__()
+           # Don't process the base class
+           if cls is __class__:
+               return
+           # Convert subclasses to ordinary dictionaries
+           return cls.__dict__.copy()
+
+It's not clear why anyone would ever do this implicitly based on inheritance
+rather than just using an explicit decorator, but the possibility seems worth
+noting.
+
+
+Open Questions
+==============
+
+Is the ``namespace`` concept worth the extra complexity?
+--------------------------------------------------------
+
+Unlike the new ``__autodecorate__`` hook the proposed ``namespace`` keyword
+argument is not automatically inherited by subclasses. Given the way this
+proposal is currently written , the only way to get a special namespace used
+consistently in subclasses is still to write a custom metaclass with a
+suitable ``__prepare__`` implementation.
+
+Changing the custom namespace factory to also be inherited would
+significantly increase the complexity of this proposal, and introduce a
+number of the same potential base class conflict issues as arise with the
+use of custom metaclasses.
+
+Eric Snow has put forward a
+`separate proposal <https://mail.python.org/pipermail/python-dev/2013-June/127103.html>`__
+to instead make the execution namespace for class bodies an ordered dictionary
+by default, and capture the class attribute definition order for future
+reference as an attribute (e.g. ``__definition_order__``) on the class object.
+
+Eric's suggested approach may be a better choice for a new default behaviour
+for type that combines well with the proposed ``__autodecorate__`` hook,
+leaving the more complex configurable namespace factory idea to a custom
+metaclass like the one shown below.
+
+
 New Ways of Using Classes
 =========================
 
@@ -428,6 +490,26 @@
 explicitly say anything one way or the other).
 
 
+Making ``__autodecorate__`` implicitly static, like ``__new__``
+---------------------------------------------------------------
+
+While it accepts the class to be instantiated as the first argument,
+``__new__`` is actually implicitly treated as a static method rather than
+as a class method. This allows it to be readily extracted from its
+defining class and called directly on a subclass, rather than being
+coupled to the class object it is retrieved from.
+
+Such behaviour initially appears to be potentially useful for the
+new ``__autodecorate__`` hook, as it would allow ``__autodecorate__``
+methods to readily be used as explicit decorators on other classes.
+
+However, that apparent support would be an illusion as it would only work
+correctly if invoked on a subclass, in which case the method can just as
+readily be retrieved from the subclass and called that way. Unlike
+``__new__``, there's no issue with potentially changing method signatures at
+different points in the inheritance chain.
+
+
 Passing in the namespace directly rather than a factory function
 ----------------------------------------------------------------
 
@@ -443,8 +525,10 @@
 ========================
 
 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__``.
+`issue tracker`_. It uses the original ``__init_class__`` naming. does not yet
+allow the implicit decorator to replace the class with a different object and
+does not implement the suggested ``namespace`` parameter for
+``type.__prepare__``.
 
 TODO
 ====

-- 
Repository URL: https://hg.python.org/peps


More information about the Python-checkins mailing list