Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the definition order of class attributes in Python?

I want to define light-weight classes that are supposed to represent data structures. As is the case with many data structures, the order of the data is important. So if I go ahead and define this:

class User(DataStructure):
    username = StringValue()
    password = StringValue()
    age = IntegerValue()

I am implying that this is a data structure where a string with the username comes first, followed by a string with the password, and finally the age of the user as an integer.

If you're familiar with Python, you'll know that the above class, User, is an object inheriting from type. It will, just like most other objects in Python, have a __dict__. And here-in lies my problem. This __dict__ is a hash map, so the order of the class attributes in the __dict__ is in no way related to their order of definition.

Is there any way I can figure out the actual definition order? I'm asking here before I go with one of the less sane methods I can think of...

Oh and just to be clear, what I want is a way to get this out of the above definition: ['username', 'password', 'age']

like image 703
Blixt Avatar asked Nov 18 '10 23:11

Blixt


2 Answers

Python 2.7 and 3.x define an OrderedDict in the collections module. I believe it uses a linked list to maintain insertion order of its items. It adds iterable methods to the standard mutable mapping methods.

You could define a metaclass which uses an OrderedDict rather than a standard unordered dict as the namespace __dict__ for your data structures classes. If you give your metaclass a special __prepare__() method you can do this. I haven't tried this but according to the docs it's possible:

From Python 3.1 Language Ref Section 3.3.3 Data Model - Customizing class creation:

If the metaclass has a __prepare__() attribute (usually implemented as a class 
or static method), it is called before the class body is evaluated with the 
name of the class and a tuple of its bases for arguments. It should return an 
object that supports the mapping interface that will be used to store the 
namespace of the class. The default is a plain dictionary. This could be used, 
for example, to keep track of the order that class attributes are declared in 
by returning an ordered dictionary.

Unfortunately the equivalent section 3.4.3 in the Python 2.7 Language Ref makes no mention of being able to substitute a class namespace dict and no mention of the __prepare__() method. So this may only be possible in Python version 3.

like image 168
Don O'Donnell Avatar answered Sep 23 '22 23:09

Don O'Donnell


This is something that is not well supported at all in Python. Django has employed metaclasses to deal with it. See this question: How does Django Know the Order to Render Form Fields?

(Summary: look at django.forms.forms.DeclarativeFieldsMetaclass, django.forms.forms.get_declared_fields and how creation_counter is used in django.forms.fields.Field.)

like image 30
Chris Morgan Avatar answered Sep 21 '22 23:09

Chris Morgan