[Python-checkins] peps: Add PEP 520: Ordered Class Definition Namespace

eric.snow python-checkins at python.org
Tue Jun 7 20:44:18 EDT 2016


https://hg.python.org/peps/rev/d4db663f019f
changeset:   6353:d4db663f019f
user:        Eric Snow <ericsnowcurrently at gmail.com>
date:        Tue Jun 07 17:44:13 2016 -0700
summary:
  Add PEP 520: Ordered Class Definition Namespace

files:
  pep-0520.txt |  219 +++++++++++++++++++++++++++++++++++++++
  1 files changed, 219 insertions(+), 0 deletions(-)


diff --git a/pep-0520.txt b/pep-0520.txt
new file mode 100644
--- /dev/null
+++ b/pep-0520.txt
@@ -0,0 +1,219 @@
+PEP: 520
+Title: Ordered Class Definition Namespace
+Version: $Revision$
+Last-Modified: $Date$
+Author: Eric Snow <ericsnowcurrently at gmail.com>
+Status: Draft
+Type: Standards Track
+Content-Type: text/x-rst
+Created: 7-Jun-2016
+Python-Version: 3.6
+Post-History: 7-Jun-2016
+
+
+Abstract
+========
+
+This PEP changes the default class definition namespace to ``OrderedDict``.
+Furthermore, the order in which the attributes are defined in each class
+body will now be preserved in ``type.__definition_order__``.  This allows
+introspection of the original definition order, e.g. by class decorators.
+
+Note: just to be clear, this PEP is *not* about changing ``__dict__`` for
+classes to ``OrderedDict``.
+
+
+Motivation
+==========
+
+Currently the namespace used during execution of a class body defaults
+to ``dict``.  If the metaclass defines ``__prepare__()`` then the result
+of calling it is used.  Thus, before this PEP, if you needed your class
+definition namespace to be ``OrderedDict`` you had to use a metaclass.
+
+Metaclasses introduce an extra level of complexity to code and in some
+cases (e.g. conflicts) are a problem.  So reducing the need for them is
+worth doing when the opportunity presents itself.  Given that we now have
+a C implementation of ``OrderedDict`` and that ``OrderedDict`` is the
+common use case for ``__prepare__()``, we have such an opportunity by
+defaulting to ``OrderedDict``.
+
+The usefulness of ``OrderedDict``-by-default is greatly increased if the
+definition order is directly introspectable on classes afterward,
+particularly by code that is independent of the original class definition.
+One of the original motivating use cases for this PEP is generic class
+decorators that make use of the definition order.
+
+Changing the default class definition namespace has been discussed a
+number of times, including on the mailing lists and in PEP 422 and
+PEP 487 (see the References section below).
+
+
+Specification
+=============
+
+* the default class *definition* namespace is now ``OrderdDict``
+* the order in which class attributes are defined is preserved in the
+  new ``__definition_order__`` attribute on each class
+* "dunder" attributes (e.g. ``__init__``, ``__module__``) are ignored
+* ``__definition_order__`` is a tuple
+* ``__definition_order__`` is a read-only attribute
+* ``__definition_order__`` is always set:
+
+  1. if ``__definition_order__`` is defined in the class body then the
+     value is used as-is, though the attribute will still be read-only
+  2. types that do not have a class definition (e.g. builtins) have
+     their ``__definition_order__`` set to ``None``
+  3. types for which `__prepare__()`` returned something other than
+     ``OrderedDict`` (or a subclass) have their ``__definition_order__``
+     set to ``None`` (except where #1 applies)
+
+The following code demonstrates roughly equivalent semantics::
+
+   class Meta(type):
+       def __prepare__(cls, *args, **kwargs):
+           return OrderedDict()
+
+   class Spam(metaclass=Meta):
+       ham = None
+       eggs = 5
+       __definition_order__ = tuple(k for k in locals()
+                                    if (!k.startswith('__') or
+                                        !k.endswith('__')))
+
+Note that [pep487_] proposes a similar solution, albeit as part of a
+broader proposal.
+
+Why a tuple?
+------------
+
+Use of a tuple reflects the fact that we are exposing the order in
+which attributes on the class were *defined*.  Since the definition
+is already complete by the time ``definition_order__`` is set, the
+content and order of the value won't be changing.  Thus we use a type
+that communicates that state of immutability.
+
+Why a read-only attribute?
+--------------------------
+
+As with the use of tuple, making ``__definition_order__`` a read-only
+attribute communicates the fact that the information it represents is
+complete.  Since it represents the state of a particular one-time event
+(execution of the class definition body), allowing the value to be
+replaced would reduce confidence that the attribute corresponds to the
+original class body.
+
+If a use case for a writable (or mutable) ``__definition_order__``
+arises, the restriction may be loosened later.  Presently this seems
+unlikely and furthermore it is usually best to go immutable-by-default.
+
+Note that ``__definition_order__`` is centered on the class definition
+body.  The use cases for dealing with the class namespace (``__dict__``)
+post-definition are a separate matter.  ``__definition_order__`` would
+be a significantly misleading name for a supporting feature.
+
+See [nick_concern_] for more discussion.
+
+Why ignore "dunder" names?
+--------------------------
+
+Names starting and ending with "__" are reserved for use by the
+interpreter.  In practice they should not be relevant to the users of
+``__definition_order__``.  Instead, for early everyone they would only
+be clutter, causing the same extra work for everyone.
+
+Why is __definition_order__ even necessary?
+-------------------------------------------
+
+Since the definition order is not preserved in ``__dict__``, it would be
+lost once class definition execution completes.  Classes *could*
+explicitly set the attribute as the last thing in the body.  However,
+then independent decorators could only make use of classes that had done
+so.  Instead, ``__definition_order__`` preserves this one bit of info
+from the class body so that it is universally available.
+
+
+Compatibility
+=============
+
+This PEP does not break backward compatibility, except in the case that
+someone relies *strictly* on ``dict`` as the class definition namespace.
+This shouldn't be a problem.
+
+
+Changes
+=============
+
+In addition to the class syntax, the following expose the new behavior:
+
+* builtins.__build_class__
+* types.prepare_class
+* types.new_class
+
+
+Other Python Implementations
+============================
+
+Pending feedback, the impact on Python implementations is expected to
+be minimal.  If a Python implementation cannot support switching to
+`OrderedDict``-by-default then it can always set ``__definition_order__``
+to ``None``.
+
+
+Implementation
+==============
+
+The implementation is found in the tracker. [impl_]
+
+
+Alternatives
+============
+
+type.__dict__ as OrderedDict
+----------------------------
+
+Instead of storing the definition order in ``__definition_order__``,
+the now-ordered definition namespace could be copied into a new
+``OrderedDict``.  This would mostly provide the same semantics.
+
+However, using ``OrderedDict`` for ``type,__dict__`` would obscure the
+relationship with the definition namespace, making it less useful.
+Additionally, doing this would require significant changes to the
+semantics of the concrete ``dict`` C-API.
+
+A "namespace" Keyword Arg for Class Definition
+----------------------------------------------
+
+PEP 422 introduced a new "namespace" keyword arg to class definitions
+that effectively replaces the need to ``__prepare__()``. [pep422_]
+However, the proposal was withdrawn in favor of the simpler PEP 487.
+
+
+References
+==========
+
+.. [impl] issue #24254
+   (https://bugs.python.org/issue24254)
+
+.. [nick_concern] Nick's concerns about mutability
+   (https://mail.python.org/pipermail/python-dev/2016-June/144883.html)
+
+.. [pep422] PEP 422
+   (https://www.python.org/dev/peps/pep-0422/#order-preserving-classes)
+
+.. [pep487] PEP 487
+   (https://www.python.org/dev/peps/pep-0487/#defining-arbitrary-namespaces)
+
+.. [orig] original discussion
+   (https://mail.python.org/pipermail/python-ideas/2013-February/019690.html)
+
+.. [followup1] follow-up 1
+   (https://mail.python.org/pipermail/python-dev/2013-June/127103.html)
+
+.. [followup2] follow-up 2
+   (https://mail.python.org/pipermail/python-dev/2015-May/140137.html)
+
+
+Copyright
+===========
+This document has been placed in the public domain.

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


More information about the Python-checkins mailing list