0
0

PythonでDictにJavaScriptのPropertyっぽくアクセスしたい

Posted at

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してないかも
      • というか,そのレベルだったらちゃんとクラスを書いてもろて

Reference

  • おおかた実装してから,ちょっといい感じのdictと、その活用方法 というQiita記事を見つけた
    • これはjson.laodのフックして,Mapというクラスを全体に当てているみたい
    • そのため,既にあるDictをどーこーするときには使えない
      • とはいえ,この人と同じでJSONをどうにかしたいだけだったので,こっちのほうがすごくきれいな実装だと思う
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0