2010-11-18 23 views
6

データ構造を表すと思われる軽量クラスを定義したいと思います。多くのデータ構造の場合と同様に、データの順序が重要です。だから私は先に行くと、これを定義する場合:Pythonでクラス属性の定義順を取得するにはどうすればよいですか?

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

を、私は、これは、パスワードの文字列が続いたユーザ名を持つ文字列が最初に来るのデータ構造、およびユーザーの最後に年齢などがあることを暗示しています整数。

あなたがPythonをよく知っているなら、上記のクラスUsertypeを継承するオブジェクトであることがわかります。 Pythonの他のほとんどのオブジェクトと同様に、__dict__があります。そして、ここに私の問題があります。この__dict__はハッシュマップなので、__dict__のクラス属性の順序は決してその定義順に関係しません。

実際の定義順序を把握する方法はありますか?私が考えることのできない、あまり意味のない方法の1つに行く前に私はここに求めています...

ああ、私が望むのは、上記の定義からこれを得る方法です。['username', 'password', 'age']

+1

、私の「あまり正気」ソリューションを中心に歩行器を構築することができますこの値で属性のリストを並べ替えます。これは、メタクラスを使用して行われます。 – Blixt

+0

あなたがここに書いたことの線に沿ってメタクラスを使用することは、私の頭に浮かぶ唯一のことです。 –

+0

さて、カウンターはDjangoチームがやった方法ですから、それを行うのが最善の方法だと私は確信しています。 –

答えて

2

これはPythonではうまくサポートされていないものです。 Djangoはメタクラスを使ってそれに対処しています。 How does Django Know the Order to Render Form Fields?

(概要::。、django.forms.forms.DeclarativeFieldsMetaclassdjango.forms.forms.get_declared_fieldsとどのようにcreation_counterdjango.forms.fields.Fieldに使用されている)

+0

Djangoのようなサウンドは、私がやろうとしていたことでした。私はそのコードを見て、東武の答えを調べるでしょう。一見すると、もっと正しいと思われます。 – Blixt

+0

TobuとDonの答えは実装するのにはいいかもしれませんが、Python 2.xではサポートされていません。今のところ、Djangoのソリューションが私にとって最良の選択です。ありがとう! – Blixt

1

あなたが明示的に属性を注文する__slots__を使用することができ、この質問を参照してください。あなたが継承するすべてのクラスがそれを定義すると、メモリと属性へのアクセスにはボーナスのパフォーマンスが得られます。

編集:最も信頼性の高い方法は、__prepare__をメタクラスで定義することです。参照ドキュメントには、complete with an example of storing attributes in an OrderedDictionaryが含まれています。

Python 2では、Djangoのフィールドクラス手法を使わないで暗黙のうちに命令を実行することはできません。Pythonはその情報を追跡しないためです。メタクラスが呼び出されるまでに失われます。

+2

'__prepare__'はPython 3でしか利用できないことに注意してください。 – aaronasterling

+0

申し訳ありませんが、私はこれをPython 2.7で動作させたいと言っています。 __prepare__は非常に新しいようです。また、__slots__を動的に割り当てることができる実装について知っていますか?私は少し試して、それを2.7で動かすことができませんでした。 – Blixt

+0

いいえ、私は "明示的なものは暗黙的なものよりも良い"と考えていました。 '__slots__'をソースに置き、' __dict__'が定義されていないことを強制するか、または非スロット属性を無視します。 – Tobu

2

一つの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__を基本クラスから取り除いて空のリストに設定するのではなく、それを拡張することはあまり難しくありません。

+1

これは論理的には洗練された解決策ですが、私が定義順序を取得する方法を探している唯一の理由は、struct defの構文をそれ以上複雑にしないためです。だから私は実際に私の構造のための特定の基本クラスを持っているので、おそらくDjangoのソリューションに行くでしょう。しかし、ありがとう! :) – Blixt

5

Python 2.7と3.xは、コレクションモジュールにOrderedDictを定義しています。私はそれがアイテムの挿入順序を維持するためにリンクリストを使用すると信じています。反復可能なメソッドを標準の変更可能なマッピングメソッドに追加します。

あなたのデータ構造クラスの名前空間__dict__としてOrderedDictではなく、標準順不同dictを使用するメタクラスを定義することができます。メタクラスに特別なメソッドを与えると、これを行うことができます。私はこれを試していないが、ドキュメントによると、それは可能です:

のPython 3.1言語のRef 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. 

残念ながら同等のセクション3.4.3でPython 2.7 Language Refでは、クラスの名前空間の代わりに__prepare__()メソッドについては言及していません。したがって、これはPythonバージョン3でのみ可能です。

0

以下は、メソッドまたは型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 
      ''' 
関連する問題