2011-06-27 8 views
14

ネストされた属性を動的に作成して参照する場合は、どのような方法が最適ですか?動的なネストされた属性をサポートするために__getattr__をオーバーライドする

私は単純なFlickrクライアントを作成していましたが、すべてのメソッドを実際に定義することなく、ドキュメント化されたAPIとできるだけ一致させたいと考えていました。

flickr = Client() 
data = flickr.people.getInfo(user_id='xxx') 

flickr.people.getInfoが直接彼らのAPIドキュメント内の対応するメソッドにマップこの場合:例えば、Flickrののflickr.people.getInfo API methodへの要求を行います。呼び出されるとpeoplegetInfoが検索されたときに作成され、適切な要求はgetInfoのパス(people.getInfo)によって決まります。この作品

class Attr(object): 
    def __init__(self, client, name, parent): 
     self._client = client 
     self._name = name 
     self._parent = parent 

    def __getattr__(self, name): 
     attr = Attr(self._client, name, self) 
     setattr(self, name, attr) 
     return attr 

    def _get_path(self, path=None): 
     if path: 
      path = '.'.join((self._name, path)) 
     else: 
      path = self._name 
     if isinstance(self._parent, Attr): 
      return self._parent._get_path(path) 
     return path 

    def __call__(self, *args, **kwargs): 
     return self._client.execute_method(self._get_path(), *args, **kwargs) 

class Client(object): 
    def __getattr__(self, name): 
     attr = Attr(self, name, None) 
     setattr(self, name, attr) 
     return attr 

    def execute_method(self, method, *args, **kwargs): 
     print method, args, kwargs 

が、ネストされた属性の割り当て/検索に対処する私のアプローチを向上させることができる場合、または待機中に潜んでいるエラーがないかどうか、私に知られずに私は興味:これは私が使用したアプローチであります。特に、与えられた属性への「パス」を理解するためのより良い方法があるのなら、私は興味があります。たとえば、Client().x.y.z()と呼び出すと、xyzが存在せず、1つずつ作成されます(__getattr__は一度に1つの属性を検索します)。 zが呼び出されるまでには、zへのパスがx.y.zであることが分かる必要があります。

+0

"ネストされた" 属性は、ほとんどの場合、ネストされたオブジェクトで処理されます。なぜPythonがこの解析を処理できるのか、名前を解析していますか? –

+0

入れ子オブジェクトを作成しています。ネストされた属性へのパスを把握する簡単な方法はありますか? – zeekay

+0

'a.b.c'を実行すると、Pythonは' 'b''を' a'' __getattr__'に与えます。あなたは、 "パス"またはそれに類するものを推論する必要はありません。 'a.b'に適切な' b'のインスタンスと 'c'と' b.c'の適切なインスタンスを提供するだけです。 –

答えて

7

これはflipyがすでにこれを行っていることを指摘してくれたThomas Kのおかげです。(これはflickrとのやりとりのための素晴らしいライブラリのようです)。クリーナーアプローチ:

class Method(object): 
    def __init__(self, client, method_name): 
     self.client = client 
     self.method_name = method_name 

    def __getattr__(self, key): 
     return Method(self.client, '.'.join((self.method_name, key))) 

    def __call__(self, **kwargs): 
     print self.method_name, kwargs 

class Client(object): 
    def __getattr__(self, key): 
     return Method(self, key) 

ほら:

>>> c = Client() 
>>> c.some.method(x=1, y=2) 
some.method {'y': 2, 'x': 1} 
関連する問題