[英]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.DeclarativeFieldsMetaclass
, django.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.