2016-11-03 11 views
2

私たちのプロジェクトでは、さまざまなソースから多数の情報を収集し、監査とデータソース間の競合を解決します各属性についてのメタデータをまとめておく必要があります。Python:クラスの変数に属性を追加して割り当て(記述子クラス)を生かす

age = 21 
age_metadata = { 
    'source' : 'office gossip', 
    'relability' : 0 
    { 

問題はクラスがこのように見えることです。

class Person 
    def __init__(self, id,): 
     self.id = id 
     self.id_meta = None 
     self.age = None 
     self.age_meta = None 
     self.name = None 

醜いように見え、すべての属性が2倍になるので、私が望むのは各属性の下にメタデータをネストすることです。だから私が必要ならば、bob.age_metaの代わりにbob.age.metaと呼ぶことができます。そして、属性を多かれ少なかれ変えずに残しておきたいと思います。私はいつも私が好きな、それを使用するために何かをしたい:

def main(): 
    bob = Person(1) 
    bob.age.meta = 'random metadata' 
    bob.age = 30 
    assert bob.age.meta == 'random metadata' 

今、私はこれが割り当て+いくつかの猿のパッチ/メタデータを保持するために魔法をmetaclassingを傍受する記述子クラスのコンボを使用して可能であるべきだと思います。..しかし、私はこれらすべての機能を初めて使い、非常に迷子になっています。ここに私の現在のスケッチです。作業コードから長く:

class AttributeWithMeta(object): 
    """interceot attribute fucntions""" 

    def __get__(self, instance, owner): 
     return self._value 

    def __set__(self, instance, value): 
     """take attribute and somehow replace it with monkey patched version""" 
     self._value = magic(value,meta) 

    @staticmethod 
    def magic(value, meta): 
     """adds meta attribute to objects regardless of type""" 
     return value_with_meta 


class Person(object): 
    age = AttributeWithMeta() 

    def __init__(self, id): 
     self.id = id 

私は正しい方向に行っていますか?私が行方不明になっているこれを行うための他の方法がいくつかありますか?私はここで不可能にしようとしていますか?

P.S最悪の場合age.get_meta()は、属性に問題がある場合は許容されます。

+0

また、これはデータベースでモデル化するのに適しています。たとえば、sqlalchemy + sqliteを実行できます。 – tdelaney

答えて

1
bob.age.meta 
^^
    | |_______ This lookup can be managed by type(bob.age) class 
    | 
    |___________ This lookup can be managed by type(bob) class, i.e. Person 

.metaの属性アクセスがbob.ageオブジェクトによって完全に処理するので、あなたのPersonクラスは、ここで問題に何の発言権を取得されていません。

Personクラスにディスクリプタを定義することにより、age属性の設定/取得/削除の動作をPersonインスタンスでどのように動作させるかを制御できます。人のインスタンスと属性の間にはown the dotがあり、そこに必要なものはすべて実行できます。しかし、そのパワーは2番目のドットまでは届かず、つまり、.agemetaの間です。

bob.ageに文字通り整数30を返すには、にはAttributeErrorを上げるのに苦労します。これは、今ではintクラスで定義されている記述子が必要であり、組み込み型をモンキーパッチすることはPythonでは不可能であるからです。とにかくterrible and unreliable hacksなしではありません。

bob.ageがオブジェクトのコンテナとそれに関連するメタデータを返すのがうれしければ、Personクラスの記述子で可能なことが可能です。しかし、bob.ageがオブジェクトだけを返すようにし、bob.age.metaがメタデータだけを返すようにしたいのであれば、あなたは間違ったツリーを吠えていると思います。あなたはボブのage属性に関連するメタデータの例bob.meta['age']のために調べることができるよう

はるかに少ない複雑な設計は、直接meta辞書を持っているために、各Personインスタンスのためになります。

+0

私は正しい軌道に乗っていると思うので、 'age'が組み込みの型ではなく、代わりに' __set__'と__meta__を除いたすべてのメソッドを代行するコンテナです。それを守る._meta – Nath

関連する問題