[Python-Dev] PEP 520: Preserving Class Attribute Definition Order (round 5)

Nick Coghlan ncoghlan at gmail.com
Fri Jun 24 18:37:55 EDT 2016

This version looks fine to me.

On 24 June 2016 at 14:52, Eric Snow <ericsnowcurrently at gmail.com> wrote:
> Background
> ==========
> When a class is defined using a ``class`` statement, the class body
> is executed within a namespace.  Currently that namespace defaults to
> ``dict``.  If the metaclass defines ``__prepare__()`` then the result
> of calling it is used for the class definition namespace.
> After the execution completes, the definition namespace namespace is
> copied into new ``dict``.  Then the original definition namespace is
> discarded.  The new copy is stored away as the class's namespace and
> is exposed as ``__dict__`` through a read-only proxy.
> The class attribute definition order is represented by the insertion
> order of names in the *definition* namespace.  Thus, we can have
> access to the definition order by switching the definition namespace
> to an ordered mapping, such as ``collections.OrderedDict``.  This is
> feasible using a metaclass and ``__prepare__``, as described above.
> In fact, exactly this is by far the most common use case for using
> ``__prepare__`` (see PEP 487).

The definition order question has been dropped from PEP 487, so this
cross-reference doesn't really make sense any more :)

> Part 2:
> * the default class *definition* namespace is now ``OrderdDict``
> The following code demonstrates roughly equivalent semantics for the
> default behavior::
>    class Meta(type):
>        @classmethod
>        def __prepare__(cls, *args, **kwargs):
>            return OrderedDict()
>    class Spam(metaclass=Meta):
>        ham = None
>        eggs = 5
>        __definition_order__ = tuple(locals())

I'd characterise this section at the language definition level as the
default class definition namespace now being *permitted* to be an
OrderedDict. For implementations where dict is ordered by default,
there's no requirement to switch specifically to

> 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 the ability to set ``__definition_order__`` manually allows
> a dynamically created class (e.g. Cython, ``type()``) to still have
> ``__definition_order__`` properly set.

This paragraph is a little confusing, since "set
``__definition_order__`` manually" is ambiguous.

"supply an explicit ``__definition_order__`` via the class namespace"
might be clearer.

> Why not 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 nearly everyone they would only
> be clutter, causing the same extra work for everyone.
> However, dropping dunder names by default may inadvertantly cause
> problems for classes that use dunder names unconventionally. In this
> case it's better to play it safe and preserve *all* the names from
> the class definition.
> Note that a couple of dunder names (``__name__`` and ``__qualname__``)
> are injected by default by the compiler.  So they will be included even
> though they are not strictly part of the class definition body.

I realised there's another important reason for doing it this way by
default: it's *really easy* to write a "skip_dunder_names" filter that
leaves out dunder names from an arbitrary interable of strings. It's
flatout *impossible* to restore the dunder attribute order if the
class definition process throws it away.


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-Dev mailing list