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をどうにかしたいだけだったので,こっちのほうがすごくきれいな実装だと思う
- これは