動機
Pythonでは、JavaScriptなどとは異なりディクショナリ要素に対しAttributeでアクセスすることはできない。
つまり、dict_obj["value"]
はOKだがdict_obj.value
とはできない。
これで不便を感じるのは、Jsonデータを扱う際だ。なんといってもJavaScript側ではAttributeでアクセスできるので、同じように書きたいというのが人情である。
そんなわけで、dict(今回はJsonオブジェクトを想定)に対しAttributeでアクセスする方法を紹介する。
実装
Pythonでは、Jsonをloadすると、ディクショナリになる。
>>> import json
>>> json.loads('{"v1":"xxxx", "v2":"vvvv"}')
{'v1': 'vvvv', 'v2': 'xxxx'}
前述したとおり、アクセスする際はobj["v1"]
という形になりobj.vi
はNGになる。
これを解決する一番簡単な方法はattrdictというライブラリを使ってしまうことだ。
ただ、わざわざインストールするのがちょっと、という場合は以下のような簡易な方法が使える。
json.loads
を行う際に、object_hook
を利用し各オブジェクトを属性アクセスを実装(__getattr__
)したクラスでラップするようにする。これで、Attribute経由で要素にアクセスできるようになる。
import json
class AttributeDict(object):
def __init__(self, obj):
self.obj = obj
def __getstate__(self):
return self.obj.items()
def __setstate__(self, items):
if not hasattr(self, 'obj'):
self.obj = {}
for key, val in items:
self.obj[key] = val
def __getattr__(self, name):
if name in self.obj:
return self.obj.get(name)
else:
return None
def fields(self):
return self.obj
def keys(self):
return self.obj.keys()
if __name__ == "__main__":
attribute_json = json.loads('{"v1":"xxxx", "v2":"vvvv"}', object_hook=AttributeDict)
print("attribute_json.v1 = {0}".format(attribute_json.v1))
json_with_array = json.loads('{"arr":[{"v":"xxxx"}, {"v":"vvvv"}]}', object_hook=AttributeDict)
print("json_with_array[0].v = {0}".format(json_with_array.arr[0].v))
実行結果
attribute_json.v1 = xxxx
json_with_array[0].v = xxxx
Attributeアクセスができるとコードの補完もきくようになるので、実装しやすくなる。お試しされたし。
参考
attrdict
using JSON keys as python attributes in nested JSON
soundcloud-python/resource.py
Sample on Gist