Abstract
PythonでDictの要素にアクセスするためにはt_dict["name"]
みたいな書き方をする
が,地味にダブルクオーテーションをつけるのがめんどくさい
@dataclass
などを用いて,データ構造を最初から決めて置くのが良い作法だが,いちいちデータ構造を設定しないと使えない
例えばJSON形式で帰ってくるWEBAPIのデータを読み出すために,不必要な情報まで記述したくはない(と書いたものの,ちゃんと調べてないので必要なところだけ書いて,残りを捨ててくれるのかもしれない?)
ということで,雑にDictにアクセスしたい人のためのラッパーを書いてみた
Code
class DictWrapper(dict):
def __getitem__(self, __key):
__t = super().__getitem__(__key)
if isinstance(__t, dict):
return DictWrapper(__t)
if isinstance(__t, list):
return ListWrapper(__t)
return __t
__getattr__ = __getitem__
class ListWrapper(list):
def __getitem__(self, __i):
__t = super().__getitem__(__i)
if isinstance(__t, list):
return ListWrapper(__t)
if isinstance(__t, dict):
return DictWrapper(__t)
return __t
Example
import json
with open("./dat.json") as f:
d = DictWrapper(json.load(f))
# YOLP Weather Data
print(d.ResultInfo.Count)
print(d.Feature[0].Geometry.Coordinates)
print(d["Feature"][0].Geometry["Coordinates"])
- YOLPのAPIを叩いてて思いついたので,YOLPの気象APIを叩いたときのサンプル
- こんな感じで,要素名にダブルクオーテーションだの,カッコだのをつけなくても動いてくれる
- 3つ目みたいな,キモい書き方も許容される(ようにした)
Mechanism
- まずクラスにおけるアトリビューションアクセス時に呼ばれる組み込み関数
__getattr__
を魔改造する必要がある - その前に,そもそもの
dict
クラスの要素取得時に呼ばれる組み込み関数__getitem__
を魔改造している - ここでのアクセスのうち,
dict
の場合はDictWrapper
を,list
の場合はListWrapper
を,それ以外はそのまま返すようにしている - これで,
dict
内部にdict
を持つような再起構造であっても,DictWarpper
を返すようになる - 同様に
list
についても,dict in list に対応するために,list
クラスのアクセスを改造し,DictWarpper
を返すようにしている.- popとかの関数で呼び出すときの動作はチェックしてないので,overloadしてないかも
- というか,そのレベルだったらちゃんとクラスを書いてもろて
- popとかの関数で呼び出すときの動作はチェックしてないので,overloadしてないかも
Reference
- おおかた実装してから,ちょっといい感じのdictと、その活用方法 というQiita記事を見つけた
- これは
json.laod
のフックして,Mapというクラスを全体に当てているみたい - そのため,既にあるDictをどーこーするときには使えない
- とはいえ,この人と同じでJSONをどうにかしたいだけだったので,こっちのほうがすごくきれいな実装だと思う
- これは