Javascript のハッシュマップはドット・ノーテーション ( dot notation )でアイテムにアクセスできますよね。でも Python の辞書ではそれができません。できたら便利だなーと考えていたらひらめいたので、 dict クラスを継承した dict2 クラスを作りました。
class dict2(dict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__dict__ = self コンストラクタ init() をオーバーライドして self.dict に self を代入する行を加えました。 ただそれだけです。
dict はオブジェクトの書き込み可能なアトリビュートを格納するために使用される辞書またはその他のマッピングオブジェクトです。 self はまさに dict を継承したマッピングオブジェクトなので、アトリビュートを格納する dict に self を代入すれば、ドット・ノーテーションでアトリビュートとして辞書のアイテムにアクセスできるようになるってわけです。
ピンとこなくても、とりあえず動作を見てみましょう。
まず IPython を起動したら、上の dict2 クラスのコードをコピペします。必ずしも IPython である必要はありませんが、解説に便利なので使います。
$ ipython
Python 3.5.2
In [1]: # ここにコピペして[Enter]こんな感じで、 Javascript のようにアトリビュートにキー名を書くとバリューが返ります。
In [2]: d2 = dict2({'abc': 123})
In [3]: d2.abc
Out[3]: 123
In [4]: d2.update({'abc': 456})
In [5]: d2.abc
Out[5]: 456ネストすればチェインもできます。
In [6]: d2.update({'ijk': dict2({'xyz': 789})})
In [7]: d2
Out[7]: {'abc': 456, 'ijk': {'xyz': 789}}
In [8]: d2.ijk.xyz
Out[8]: 789さらに、ドット・ノーテーションで辞書のアイテムを追加することもできます。
In [9]: d2.uvw = 'foobar'
In [10]: d2['uvw']
Out[10]: 'foobar'もちろん、ドット・ノーテーションで辞書のアイテムを更新できます。
In [11]: d2.abc = 321
In [12]: d2['abc']
Out[12]: 321万能すぎる…
なんだろう、このダクトテープとか結束バンドを使った修理に似た感覚は。
注意点としては、キーに予約語とか演算子の記号とか数値リテラルとか変数名に使えない文字列が入ると、辞書のキーとしては問題ないですが、ドット・ノーテーションだとシンタックスエラーになります。あと、すでにあるアトリビュート名とキーが衝突すると上書きされるので気をつけましょう。そういう諸々をエラーにしたいときは、 init() に加えて setitem() とか update() とかもオーバーライドしてバリデーションすればいいんじゃないですかね。他にも副作用があるかもしれません。