如何获得Python中类属性的定义顺序?

2024-05-19 13:32:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我想定义一些轻量级的类来表示数据结构。与许多数据结构的情况一样,数据的顺序非常重要。所以如果我继续定义这个:

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

我的意思是这是一个数据结构,其中首先是用户名的字符串,然后是带有密码的字符串,最后是作为整数的用户年龄。在

如果您熟悉Python,就会知道上面的类User,是从type继承的对象。它将像Python中的大多数其他对象一样,有一个__dict__。我的问题就在这里。这个__dict__是一个哈希映射,因此__dict__中类属性的顺序与它们的定义顺序没有任何关系。在

有没有办法让我算出实际的定义顺序?在我用一种我能想到的不太明智的方法之前,我要问一下。。。在

哦,我想说清楚,我想要的是一种从上述定义中得到的方法:['username', 'password', 'age']


Tags: 数据对象方法字符串数据结构age定义顺序
3条回答

python2.7和3.x在collections模块中定义了一个OrderedDict。我相信它使用一个链表来维护其项的插入顺序。它将iterable方法添加到标准的可变映射方法中。在

您可以定义一个元类,它使用OrderedDict而不是标准的无序dict作为数据结构类的命名空间__dict__。如果你给你的元类一个特殊的__prepare__()方法,你可以这样做。我没试过,但根据文件,这是可能的:

来自Python3.1语言参考第3.3.3节数据模型-自定义类创建:

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.

不幸的是,python2.7语言Ref中的等效部分3.4.3没有提到能够替换类名称空间dict,也没有提到__prepare__()方法。所以这可能只有在pythonversion3中才可能实现。在

这在Python中根本没有得到很好的支持。Django已经使用元类来处理它。看这个问题:How does Django Know the Order to Render Form Fields?

(总结:看看django.forms.forms.DeclarativeFieldsMetaclassdjango.forms.forms.get_declared_fields,以及creation_counter在{}中是如何使用的。)

一种比Django的方法更通用的方法是,Python2中可用的__slots__,这就是元类:

class OrderedTypeMeta(type):
    def __new__(mcls, clsname, bases, clsdict):
        attrs = clsdict.get('_attrs_', [])
        attrnames = []
        for name, value in attrs:
            clsdict[name] = value
            attrnames.append(name) 
        clsdict['_attrs_'] = attrnames
        return super(OrderedTypeMeta, mcls).__new__(mcls, clsname, bases, clsdict)


class User(DataStructure):
    __metaclass__ = OrderedTypeMeta
    _attrs_ = (('name', StringValue()),
               ('password', StringValue()),
               ('age', IntegerValue()))

我说它比django的方法更通用,因为您不需要属性是特定类的实例,任何值都可以。它也比__slots__更通用,因为您仍然可以为类的实例分配属性(尽管这可能不需要:在这种情况下,我更喜欢__slots__)。在Python3中,我更喜欢__prepare__。在

除了它有点难看之外,它的主要缺点是它不能与继承一起工作。将__attrs__从基类中取出并扩展它而不是将其设置为空列表并不困难。在

相关问题 更多 >