[Python-Dev] Preserving the definition order of class namespaces.

Eric Snow ericsnowcurrently at gmail.com
Sun May 24 03:15:35 CEST 2015


tl;dr Are there any objections to making making the default
cls.__prepare__ return OrderedDict instead of dict (and preserve that
order in a list on the class)?

A couple years ago [1][2] I proposed making class definition
namespaces use OrderedDict by default.  Said Guido [3]:

    I'm fine with doing this by default for a class namespace; the type of
    cls.__dict__ is already a non-dict (it's a proxy) and it's unlikely to
    have 100,000 entries.

It turns out making cls.__dict__ an OrderedDict isn't reasonably
tractable (due to the concrete API v. subclasses), but really that
isn't what I was looking for anyway.

Regardless, since it's been a while I just want to run the proposal by
the group again.  I'm hopeful about landing my C implementation of
OrderedDict [4] in the next few days.  Also, I have a patch up [5]
that implements using OrderedDict for class definitions.  So mostly I
just want to double check that I'm still good to go.

Just to be clear on what I'm proposing specifically, I've summed it up below.

-eric

---------------------

Currently if you want to preserve the order of a class definition you
have to use a metaclass with a __prepare__ method (see PEP 3115).
However, as that PEP points out [6], the common case for __prepare__
is to use OrderedDict.  I'm proposing that we return OrderedDict() by
default from __prepare__.  Considering the common case, we should also
expose that definition order on the class afterward since otherwise
the extra information from the class definition namespace is discarded
(type.__new__ copies it into a dict which is then used for
cls.__dict__).

So the key changes are:

* use OrderedDict by default for class definition namespace (e.g. from
type.__prepare__)
* expose that definition order as cls.__definition_order__ (a list)

(Note that I will not be changing the actual type of cls.__dict__
(i.e. tp_dict) which will remain a dict.)

The effect of the change would be that the following are basically
equivalent (relative to the the definition namespace):

    class Meta(type):
        @classmethod.
        def __prepare__(meta, *args, **kwargs):
            return OrderedDict()

    class SpamOld(metaclass=Meta):
        a = 1
        b = 2
        c = 3
        __definition_order__ = list(locals())

    class SpamNew:
        a = 1
        b = 2
        c = 3

    assert SpamOld.__definition__order == SpamNew.__definition_order__

The key differences are:

* for SpamNew you don't need to use a metaclass [7][8]
* for SpamNew you don't need to rely on the behavior of locals()
* for SpamNew the class definition isn't cluttered with extra
boilerplate for __definition_order__
* class decorators that care about definition order [9] don't have to
require that classes like SpamNew manually preserve that order somehow

The patch for the change is pretty minimal. [5]

Also, Nick Coghlan recently expressed that he favored using
OrderedDict by default over the alternative presented by PEP 422/487.
[10]


[1] https://mail.python.org/pipermail/python-ideas/2013-February/019690.html
[2] https://mail.python.org/pipermail/python-dev/2013-June/127103.html
[3] Guido: https://mail.python.org/pipermail/python-ideas/2013-February/019704.html
[4] http://bugs.python.org/issue16991
[5] http://bugs.python.org/issue24254
[6] see the "Alternate Proposals" section of
https://www.python.org/dev/peps/pep-3115/
[7] PEPs 422 and 487 relatedly focus on the benefits of reducing the
need to use metaclasses
[8] https://mail.python.org/pipermail/python-ideas/2013-February/019706.html
[9] see "Key points" on
https://mail.python.org/pipermail/python-dev/2013-February/124439.html
[10] Nick: https://mail.python.org/pipermail/python-ideas/2015-March/032254.html


More information about the Python-Dev mailing list