はてだBlog(仮称)

私的なブログど真ん中のつもりでしたが、気づけばWebサイト系のアプリケーション開発周りで感じたこと寄りの自分メモなどをつれづれ述べています。2020年6月現在、Elasticsearch、pandas、CMSなどに関する話題が多めです。...ですが、だんだんとより私的なプログラムのスニペット置き場になりつつあります。ブログで述べている内容は所属組織で販売している製品などに関するものではなく、また所属する組織の見解を代表するものではありません。

Pythonのネストされたdictに「a.b.c.d」のようなJavaScript風のアクセスを行う小品のスニペット例

Pythonのdict型のようなデータの配下の特定のプロパティに、「a.b.c.d」のような表記でアクセスできると、試験ツールやチェックツールで確認したいパターンを外部から入力として与えやすくなにかと便利だと感じています。

こういった使い捨てツールなどのために、言語をかえたりしながら、アクセスDSLの関数が必要になることが一年のうち2、3回あります。

基本は再帰を使うことになり、毎度その場その場の要件や気分を表していておもしろいなと思ったのでメモってみました。

今回はこんな感じ↓

hoge.py(Pythonです)

d = {
    "a": {"b": {"c": "あああ", "d": ["いいい"]}},
    "x": "ううう"
}

# 指定のフィールドを取り出す
def findfield(obj, path):
    k = path.pop(0)
    if isinstance(obj, dict):
        if len(path) == 0:
            if k in obj.keys():
                return obj[k]
            return None
        return findfield(obj[k], path)
    return None


# 指定のフィールドを削除する
def delfield(obj, path):
    k = path.pop(0)
    if isinstance(obj, dict):
        if len(path) == 0:
            obj.pop(k, None)
            return
        delfield(obj[k], path)


print('f1', findfield(d, 'a.b'.split('.')))

print('f2', findfield(d, 'a.b.c'.split('.')))

print('f3', findfield(d, 'a.b.d'.split('.')))

print('f4', findfield(d, 'a.err'.split('.')))

print('f5', findfield(d, 'a.b.d.err'.split('.')))

delfield(d, 'a.b.d.err'.split('.'))
print('d1', d)

delfield(d, 'a.err'.split('.'))
print('d2', d)

delfield(d, 'a.b.d'.split('.'))
print('d3', d)

delfield(d, 'a.b.c'.split('.'))
print('d4', d)

delfield(d, 'a.b'.split('.'))
print('d5', d)


なお、「a.b.c.d」のようなアクセスに向かないプロパティにぶち当たった場合、例えば、a.b.cがリストの場合は強制的にNoneを戻すこととしています。

hoge.pyの実行結果

f1 {'c': 'あああ', 'd': ['いいい']}
f2 あああ
f3 ['いいい']
f4 None
f5 None
d1 {'a': {'b': {'c': 'あああ', 'd': ['いいい']}}, 'x': 'ううう'}
d2 {'a': {'b': {'c': 'あああ', 'd': ['いいい']}}, 'x': 'ううう'}
d3 {'a': {'b': {'c': 'あああ'}}, 'x': 'ううう'}
d4 {'a': {'b': {}}, 'x': 'ううう'}
d5 {'a': {}, 'x': 'ううう'}

大事なことを見逃しているかもしれないが、今回の用途ぐらいには対応できた気がする。