追記(2017.02.27)
執筆当時は知りませんでしたが、dictを属性でアクセスする目的だけならattrdictがドンピシャです。
以下のように利用できます(公式ドキュメントより引用)
from attrdict import AttrDict a = AttrDict({'foo': 'bar'}) a.foo
'bar'
a['foo']
'bar'
# 概要と動機
jsonを返すWeb-APIのレスポンスをpythonで扱う時のこと。
だいたいは階層が深く、一階層ごとに値をチェックしながら参照するのがめんどくさい。
なので、以下のような実行結果が得られる _parse_ 関数があったら便利だなと思った次第です。
```python
some_dict = {
"path":{
"to":{
"target":
"key": 1 }}}
# expected return: 1
parse(some_dict, "/path/to/target/key")
# expected return: None
parse(some_dict, "/fake/key")
動作的には一種のクエリパーサ...っぽい感じもする。
検討
- 再帰使えばそれなりにサクッと書けそう
- パス形式っぽく参照できれば...と思ってたけど、要は辞書型対応したsplitを書けばよい
- デリミタが "/" 固定だと、キーが "a/b" とかだと破綻する
- ならばデリミタはkwarg形式で指定できればOK
実装
最低限の実装。
d = {
'a': 1,
'b': [1, 2, 3],
'c': {
'ca': 1,
'cb': [2, 3, 4] }}
d2 = {
'a': 1,
'a/x': 2,
'b': {
'ba': 100 }}
def dparse(dic, p, sep="/", default=None):
lis = p.split(sep)
def _(dic, lis, sep, default):
if len(lis) == 0:
return default
if len(lis) == 1:
return dic.get(lis[0], default)
else:
return _(dic.get(lis[0], {}), lis[1:], sep, default)
return _(dic, lis, sep=sep, default=None)
if __name__=="__main__":
print dparse(d, "a") # 1
print dparse(d, "c/cb") # [2, 3, 4]
print dparse(d2, "a/x", sep=":") # 2
print dparse(d2, "b:ba", sep=":") # 100
dict を parse する感じのイメージで dparse と、適当に命名。
後記的なもの
色々と抜け穴はあるはずなので、そのあたりはツッコミ待ちです。
すぐ思いつくところだと、「valueとしてのNone」が含まれているとこの関数は破綻します。「存在しない」と、「値としてのNone」を区別できないので論理的なエラーの元。
default 引数をNone以外に指定したことろで、本質は同じ。
「存在しない」のケースは素直にraiseするのがいいのかもしれません。
これを読んだ方へ
この程度のユーティリティなら多分車輪の再発明だと思うので、今回の目的に叶う既存の良い手段があれば知りたいです。
コード or 設計がダサい、こう書け!のご指摘も歓迎。
関数名も、適切なネーミングが思いつかなくてひとまず dparse としましたが、名は体を表す的な表現ができてないのでそのへんもいいアイデアがあれば。