Help us understand the problem. What is going on with this article?

[Python] dict型にパスっぽくアクセスできるユーティリティ作ってみた

More than 1 year has passed since last update.

追記(2017.02.27)

執筆当時は知りませんでしたが、dictを属性でアクセスする目的だけならattrdictがドンピシャです。

以下のように利用できます(公式ドキュメントより引用)

from attrdict import AttrDict
a = AttrDict({'foo': 'bar'})
a.foo
'bar'
a['foo']
'bar'

概要と動機

jsonを返すWeb-APIのレスポンスをpythonで扱う時のこと。
だいたいは階層が深く、一階層ごとに値をチェックしながら参照するのがめんどくさい。
なので、以下のような実行結果が得られる parse 関数があったら便利だなと思った次第です。

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

dictparse する感じのイメージで dparse と、適当に命名。

後記的なもの

色々と抜け穴はあるはずなので、そのあたりはツッコミ待ちです。
すぐ思いつくところだと、「valueとしてのNone」が含まれているとこの関数は破綻します。「存在しない」と、「値としてのNone」を区別できないので論理的なエラーの元。
default 引数をNone以外に指定したことろで、本質は同じ。

「存在しない」のケースは素直にraiseするのがいいのかもしれません。

これを読んだ方へ

この程度のユーティリティなら多分車輪の再発明だと思うので、今回の目的に叶う既存の良い手段があれば知りたいです。

コード or 設計がダサい、こう書け!のご指摘も歓迎。

関数名も、適切なネーミングが思いつかなくてひとまず dparse としましたが、名は体を表す的な表現ができてないのでそのへんもいいアイデアがあれば。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away