Python: 辞書の値を属性参照する (AttrDict)

辞書の値を属性参照 (dic["key"] ではなく dic.keyでアクセスする) したいケースがしばしばあります。JSON形式の設定ファイルを読み込んで、オブジェクトの初期化に使うなどです。

そんなときに便利なAttrDictを紹介します。

typeを使えば良いのでは?

組み込み関数typeでも同じようなことはできますが、値が辞書 (key2) の場合はそのまま辞書変数となってしまいます。そのため d.key2.key21 というアクセスはエラーとなります。あまり直感的ではないです。

d = {"key1": "value1", "key2": {"key21": 1, "key22": None}}

o = type("dummy", (object,), d)

print(o.key1, type(o.key1))
# value1 <class 'str'>

print(o.key2, type(o.key2))
# {'key21': 1, 'key22': None} <class 'dict'>

print(o.key2.key21)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# AttributeError: 'dict' object has no attribute 'key21'

AttrDict

AttrDictはこういった辞書の中の辞書も含めて属性参照できるようにオブジェクトを変換してくれます。

github.com

$ pip install attrdict

使い方はAttrDictをimportして obj = AttrDict(dic) で変換。あとはtypeと同じようにobj.keyでアクセスできます。

from attrdict import AttrDict

d = {"key1": "value1", "key2": {"key21": 1, "key22": None}}

o = AttrDict(d)

print(o, type(o))
# AttrDict({'key1': 'value1', 'key2': {'key21': 1, 'key22': None}}) <class 'attrdict.dictionary.AttrDict'>

print(o.key1, type(o.key1))
# value1 <class 'str'>

辞書型の変数も、AttrDict型オブジェクトへ再帰的に変換されています。そのためo.key2.key21でも何ら問題なくアクセスできます。

print(o.key2, type(o.key2))
# AttrDict({'key21': 1, 'key22': None}) <class 'attrdict.dictionary.AttrDict'>

print(o.key2.key21, type(o.key2.key21))
# 1 <class 'int'>