类中的属性顺序

时间:2013-11-11 17:23:27

标签: python oop wtforms

在python中保证保持类中属性的顺序吗?这是如何保证的?指定手册中的哪个位置?

这将声明性地将字段定义为类属性:

class MyForm(Form):
    first_name = TextField(u'First Name', validators=[validators.required()])
    last_name  = TextField(u'Last Name', validators=[validators.optional()])
    ...


def get(self):
    form = MyForm(self.request.arguments)
    form=form
    self.render('forms.html', form=form)

即使我有 n 项目,第一个名称将始终是第一个项目而最后一个名称是第二个名称?

2 个答案:

答案 0 :(得分:7)

不,属性的顺序通常是保证,因为Python将属性存储在字典中。

相反,wtforms使用特殊技巧来检测定义字段的顺序,这可以解决这个问题。每次创建Field对象时,计数器都会递增,并为字段实例分配唯一编号。这使得对象可以订购:

class UnboundField(object):
    _formfield = True
    creation_counter = 0

    def __init__(self, field_class, *args, **kwargs):
        UnboundField.creation_counter += 1
        # [...]
        self.creation_counter = UnboundField.creation_counter

因此,Field个实例的creation_counter值会在每次将新字段添加到表单时递增。

FormMeta类然后在字段上使用该值以正确的顺序对它们进行排序:

fields.sort(key=lambda x: (x[1].creation_counter, x[0]))

答案 1 :(得分:1)

通过实例化元类来创建新类,就像通过实例化类来创建新的实例对象一样。类声明如:

class MyForm(Form):
    first_name = TextField(u'First Name', validators=[validators.required()])
    last_name  = TextField(u'Last Name', validators=[validators.optional()])    

等效于以下调用,其中type是默认的python元类:

MyForm = type('MyForm', (Form,), {'first_name': TextField(u'First Name', validators=[validators.required()]), 
                                  'last_name': TextField(u'Last Name', validators=[validators.optional()])}

由于类名称空间作为dict传递,并且dicts具有任意顺序,因此不保留顺序。

保持顺序记录的一种方法是让TextField类本身记录为每组参数调用它的顺序。然后,您可以恢复声明字段的顺序。这可能是Django在幕后所做的事情。