簡體   English   中英

如何在Python中獲取類屬性的定義順序?

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

我想定義應該代表數據結構的輕量級類。 與許多數據結構的情況一樣,數據的順序很重要。 所以,如果我繼續定義:

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

我暗示這是一個數據結構,其中首先是帶有用戶名的字符串,后跟帶有密碼的字符串,最后是用戶的年齡作為整數。

如果你熟悉Python,你就會知道上面的類User是一個繼承自type的對象。 就像Python中的大多數其他對象一樣,它會有__dict__ 這里存在我的問題。 這個__dict__是一個哈希映射,因此__dict__類屬性的順序與它們的定義順序無關。

有什么方法可以找出實際的定義順序嗎? 在我采用一種我能想到的不那么理智的方法之前,我在這里問...

哦,只是為了清楚,我想要的是一種方法來解決上述定義: ['username', 'password', 'age']

Python 2.7和3.x在collections模塊中定義OrderedDict 我相信它使用鏈表來維護其項目的插入順序。 它為標准的可變映射方法添加了可迭代的方法。

您可以定義一個元類,它使用OrderedDict而不是標准的無序dict作為數據結構類的命名空間__dict__ 如果為元類賦予特殊的__prepare__()方法,則可以執行此操作。 我沒有試過這個,但根據文檔,它是可能的:

從Python 3.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.

不幸的是,Python 2.7語言參考中的等效部分3.4.3沒有提到能夠替換類命名空間字典而沒有提及__prepare__()方法。 所以這可能只適用於Python版本3。

這在Python中根本不受支持。 Django使用元類來處理它。 看到這個問題: Django如何知道呈現表單字段的順序?

(小結:看django.forms.forms.DeclarativeFieldsMetaclassdjango.forms.forms.get_declared_fields以及如何creation_counter在使用django.forms.fields.Field 。)

比Django的方法更通用的一種方法, __slots__ python 2中可用的方法是這個元類:

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__並擴展它而不是將其設置為空列表並不太難。

您可以使用__slots__顯式排序屬性。 如果您繼承的每個類都定義它,那么內存和屬性訪問會帶來額外的性能提升。

編輯:最可靠的方法是在元類中定義__prepare__ 參考文檔具有它, 以及在OrderedDictionary中存儲屬性的示例

沒有Django的字段類技術,你不能在Python 2中隱式地使用順序,因為Python只是不跟蹤那些信息; 它在調用元類時丟失了。

下面讓我捕獲作為方法或類型struct的屬性的順序。 我還沒有嘗試過內置類型。 然后你可以在孩子周圍建造一個助行器

class ordered_type(type):
    __ordernate__ = 0
    def __new__(meta, name, baseclasses, dct):
        new = super(Type, meta).__new__(meta, name, baseclasses, dct)
        new.__ordernate__ = Type.__ordernate__
        Type.__ordernate__ += 1        
        def key(x):
            from inspect import ismethod
            if ismethod(x):
                return x.im_func.__code__.co_firstlineno
            elif isinstance(x, type):
                return x.__ordernate__ + 1000000
        new.__children__ = sorted(
            [getattr(new, x) for x in dir(new) if not x.startswith('__')],
            key=key)

class struct(object):
    __metaclass__ = ordered_type

#use case
class A(struct):
    '''Description of class A
    '''
    def name(self):
        '''The name of instance of A
        '''
    class B(struct):
        '''Description of class B
        '''
        def name(self):
            '''The name of instance of B
            '''

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM