Getting the definition order of class attributes in python¶
Same question was in StackOverflow, but the answer was not so soft on me.
It gave me a some hints, but it actually says ‘Watch a code’. Ok, so I read the code and understood that behavior, I will write that description here.
Why is definition order necessary¶
The best example is on Form libraries. The definition order will affect to rendering order directory.
Consider on a suprious form library, like this:
class MyForm(Form):
name = StringField()
text = StringField()
and it should be rendered that the first place is name and the second text like this oreder:
<input value='name' />
<input value='text' />
Of cause, general form libraries consider the definition order, such as Djnago Form, deform (actually, colander’s behavior).
On my case, I should handle it on creating Uiro framework, definition views in controller.
Answer¶
To handle the order, you should place a counter. The counter will be increased on each constraction of orderd attributes. And then, each attributes stores that counter value to it’s own.
>>> import itertools
>>> class Field(object):
... _counter = itertools.count()
... def __init__(self):
... self._order = next(Field._counter)
...
>>> class Form(object):
... name = Field()
... text = Field()
...
>>> Form.name
<__main__.Field object at 0x7f0abfb26250>
>>> Form.name._order
0
>>> Form.text._order
1
Ok, seems good. Then, apply this practice on writing metaclass:
>>> class FormMetaClass(type):
... def __new__(cls, name, base, attrs):
... new_class = super(FormMetaClass, cls).__new__(cls, name, base, attrs)
...
... fields = [(name, value) for name, value in attrs.items()
... if isinstance(value, Field)]
...
... # sorting manually corresponds to the definision order of Fields.
... fields.sort(key=lambda e: e[1]._order)
...
... new_class.fields = fields
... return new_class
...
>>> class Form(metaclass=FormMetaClass):
... name = Field()
... text = Field()
...
>>> Form.fields[0]
('name', <__main__.Field object at 0x7f0abfb26410>)
>>> Form.fields[1]
('text', <__main__.Field object at 0x7f0abfb26490>)
sweet, the definition order didn’t lost. In __new__ method, the fields before sorted, the order of Fields is not considered in fields, because the attrs is just a dictionary. so we should apply _oreder attribute to Field and re-consider the order manually using that _order.
I used this tips on this change, check it out.
