skip to navigation
skip to content

Python Wiki

Python Insider Blog

Python 2 or 3?

Help Fund Python

[Python resources in languages other than English]

Non-English Resources

Add an event to this calendar.

Times are shown in UTC/GMT.

Add an event to this calendar.

PEP:520
Title:Ordered Class Definition Namespace
Version:502e69ccfe29
Last-Modified:2016-06-11 20:38:55 -0600 (Sat, 11 Jun 2016)
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, 11-Jun-2016

Abstract

When a class is defined using a class statement, the class body is executed within a namespace. After the execution completes, that namespace is copied into new dict and 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.

This PEP changes the default class definition namespace to OrderedDict. The long-lived class namespace (__dict__) will remain a dict. Furthermore, the order in which the attributes are defined in each class body will now be preserved in the __definition_order__ attribute of the class. This allows introspection of the original definition order, e.g. by class decorators.

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 (or None)
  • __definition_order__ is a read-only attribute
  • __definition_order__ is always set:
    1. if __definition_order__ is defined in the class body then it must be a tuple of identifiers or None; any other value will result in TypeError
    2. classes that do not have a class definition (e.g. builtins) have their __definition_order__ set to None
    3. classes 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 for the default behavior:

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 not (k.startswith('__') and
                                         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 feature focused on more than class definition.

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 nearly everyone they would only be clutter, causing the same extra work for everyone.

Why None instead of an empty tuple?

A key objective of adding __definition_order__ is to preserve information in class definitions which was lost prior to this PEP. One consequence is that __definition_order__ implies an original class definition. Using None allows us to clearly distinquish classes that do not have a definition order. An empty tuple clearly indicates a class that came from a definition statement but did not define any attributes there.

Why None instead of not setting the attribute?

The absence of an attribute requires more complex handling than None does for consumers of __definition_order__.

Why constrain manually set values?

If __definition_order__ is manually set in the class body then it will be used. We require it to be a tuple of identifiers (or None) so that consumers of __definition_order__ may have a consistent expectation for the value. That helps maximize the feature's usefulness.

Why is __definition_order__ even necessary?

Since the definition order is not preserved in __dict__, it is 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

<class>.__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 then be used as the mapping proxied as __dict__. Doing so would mostly provide the same semantics.

However, using OrderedDict for __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.