辞書にオブジェクトっぽくアクセスする
はじめに
pythonでは2.6以降ならばjsonライブラリを使ってjsonを簡単に使えて便利です。
jsonライブラリを使うと、json文字列をparseして辞書で取得することができるのですが、
jsonの階層が深いとオブジェクトっぽくアクセスできないかなーと思うときがあります。
既に同じようなことをやってる人がいそうですが、時間があったので軽く実装してみました。
ソース
class DictAccessLikeObj(dict): """ >>> DictAccessLikeObj({"foo":"hoge"}).foo 'hoge' >>> DictAccessLikeObj({u"foo":[{u"bar":u"baz"}]}).foo[0].bar u'baz' >>> DictAccessLikeObj({u"foo":[[1,2,3]]}).foo[0][2] 3 """ def __getattr__(self, key): if key in self: val = self[key] if isinstance(val, dict): return self.__class__(val) elif isinstance(val, list): return [self.__class__(v) if isinstance(v, dict) else v for v in val] else: return val else: raise AttributeError, key
使い方
import json test = DictAccessLikeObj(json.loads(''' {"states" : [ {"foo":"hoge"}, 123, {"baz":"piyo"} ] } ''')) print(test.states) # => [{u'foo': u'hoge'}, 123, {u'baz': u'piyo'}] print(test.states[0]) # => {u'foo': u'hoge'} print(test.states[2].baz) # => piyo
まとめ
うまいこと辞書をラップしてやることで実現できました。
お分かりだと思いますが、辞書としてアクセスしたほうが動作は早いです。
こんなこともできるってことが分かったのが今回の収穫ですね。
__getattr__は初めて使ったのですが、使い方が分かれば、抽象的な処理を行わせるときの強力な道具になりそうです。
参考
追記(2011/6/22 AM1:00)
@pokarim さんからtwitterでコメントがありました。
@Masahito class D(dict):__getattr__ = dict.__getitem__json.loads('{"1":[{"a":1},2]}', object_hook=D) でもいけるみたいです。いま調べて知ったんですが。
2011-06-22 00:52:17 via web to @Masahito
import json class D(dict): __getattr__ = dict.__getitem__ test = json.loads('{"foo":[{"a":1},2]}', object_hook=D) print(test.foo[0].a) => 1
おぉー!こんなに簡単にかけるとは思わなかった。ありがとうございました。