warvariuc
warvariuc

Reputation: 59674

Metaclass - cannot replace class dict

Running this (Python 3.3.1):

from collections import OrderedDict


class MyType(type):
    @classmethod
    def __prepare__(*args):
        return OrderedDict()


class MyClass2(metaclass=MyType):

    attr1 = 1
    attr2 = 2
    attr3 = 3
    attr4 = 4
    attr5 = 5

    def __init__(self):
        self.attr6 = 6

    def func(self):
        pass



print(MyClass2.__dict__.items())

i am getting:

dict_items([('__weakref__', <attribute '__weakref__' of 'MyClass2' objects>), ('__dict__', <attribute '__dict__' of 'MyClass2' objects>), ('__init__', <function MyClass2.__init__ at 0x7f08a106dc20>), ('__doc__', None), ('attr4', 4), ('attr5', 5), ('attr2', 2), ('attr3', 3), ('attr1', 1), ('func', <function MyClass2.func at 0x7f089f995c20>), ('__module__', '__main__')])

The class attributes are not sorted by their definition order.

What am i doing wrong to use OrderedDict as class __dict__?

Upvotes: 3

Views: 503

Answers (1)

Duncan
Duncan

Reputation: 95742

The __prepare__ method in a mataclass allows you to provide your own custom object in place of the dict used for class initialisation. However you cannot change the type of object actually used by the class, that will be an instance of an internal type known as mappingproxy and is unordered. If you want to preserve the order in which the attributes where defined you must store that separately:

class OrderedClass(type):
         @classmethod
         def __prepare__(metacls, name, bases):
            return OrderedDict()

         def __new__(cls, name, bases, classdict):
            result = type.__new__(cls, name, bases, classdict)
            result.member_names = list(classdict.keys())
            return result


class MyClass2(metaclass=OrderedClass):

    attr1 = 1
    attr2 = 2
    attr3 = 3
    attr4 = 4
    attr5 = 5

    def __init__(self):
        self.attr6 = 6

    def func(self):
        pass

>>> MyClass2.member_names
['__module__', '__qualname__', 'attr1', 'attr2', 'attr3', 'attr4', 'attr5', '__init__', 'func']

Upvotes: 6

Related Questions