深いネストを持った辞書型から安全かつ簡潔に値を取り出したいので調べた
-
結論
jmespathライブラリを使うと良い
やりたいこと
今まで深いネストをした辞書から値を取り出す際には
d = {"hoge": {"fuga": {"piyo": 1}}} v = d.get("hoge", {}).get("fuga", {}).get("piyo") # v = 1
としていたが、非常に長ったらしいのでやめたかった。
ネストをピリオドでつないで取得できるのが理想。調べたところ、ライブラリでの解決策としては「辞書型を拡張したクラスを使う」パターンと、「関数を通して辞書から指定の値を取り出す」パターンがあるらしい。
「辞書型を拡張したサブクラスを使う」パターン
pip install python-box
from box import Box d = {"hoge": {"fuga": {"piyo": 1}}} mybox = Box(d, box_dots=True, default_box=True) v = mybox["hoge.fuga.piyo"] # v = <Box: 1>
default_box=Trueでパスが存在しないときにも空のBoxオブジェクトが帰ってくる。
想像していたものに近いがサブクラスの宣言がいちいち必要なのが面倒。「関数を通して辞書から指定の値を取り出す」パターン
pip install jmespath
import jmespath d = {"hoge": {"fuga": {"piyo": 1}}} v = jmespath.search("hoge.fuga.piyo", d) # v = 1
これでよさそう。
-
JavaScriptも同様の問題があり、ライウラリー探したけど、いまいちなので自作しました。
pythonも多分同じ方法で出来ると思います。/**
- オブジェクトのプロパティの存在チェック&取得
- パラメータ:
-
obj : 任意のオブジェクト
-
path : チェックしたいデータがあるプロパティをパス形式で渡す (フォーマット例 "a.b.c")
- 戻り値:
-
プロパティにデータがある場合はデータを返し、無い場合はnotExistの指定が無い場合は"undefined"を返す
*/
Object.propatyGet = function(obj, path, notExist=undefined) {
return path.split('.').reduce((obj, prop) => { return obj && obj[prop] ? obj[prop] : notExist; }, obj);
}