[解決済み] Pythonのハッシュ化可能なディクショナリ
質問
練習として、そしてほとんど私自身の楽しみのために、私はバックトラックパクラットパーサーを実装しています。 このためのインスピレーションは、(あなたが通常それらを見つけるシンタックスフリーのLisp方言とは対照的に)アルゴル的な言語でハイジェニックマクロがどのように動作するかについてより良い考えを持ちたいことです。 このため、入力の異なるパスでは異なる文法が表示される可能性があり、キャッシュされた解析結果は、キャッシュされた解析結果と一緒に現在のバージョンの文法も保存しない限り、無効となります。 ( EDIT しかし、私はコレクションを変更できるようなインターフェイスを公開するつもりはないので、MutableコレクションでもImmutableコレクションでもかまいません。)
問題は、pythonのdictsは他のdictsのキーとして表示されないことです。 タプルを使っても(どうせやるのですが)役に立ちません。
>>> cache = {}
>>> rule = {"foo":"bar"}
>>> cache[(rule, "baz")] = "quux"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
ずっとタプルでなければならないのでしょう。 Pythonの標準ライブラリは、私が必要とするものをおおよそ提供してくれます。
collections.namedtuple
は非常に異なった構文を持っていますが
は
がキーとして使われます。
>>> from collections import namedtuple
>>> Rule = namedtuple("Rule",rule.keys())
>>> cache[(Rule(**rule), "baz")] = "quux"
>>> cache
{(Rule(foo='bar'), 'baz'): 'quux'}
わかりました。 しかし、私は使いたいルールのキーの可能な組み合わせごとにクラスを作らなければなりません。これはそれほど悪いことではなく、それぞれのパースルールは使用するパラメータを正確に知っているので、そのクラスはルールをパースする関数と同時に定義することができるのです。
編集:追加の問題点として
namedtuple
のもう一つの問題は、それらが厳密に位置決めされていることです。 異なるように見える 2 つのタプルは、実際には同じである可能性があります。
>>> you = namedtuple("foo",["bar","baz"])
>>> me = namedtuple("foo",["bar","quux"])
>>> you(bar=1,baz=2) == me(bar=1,quux=2)
True
>>> bob = namedtuple("foo",["baz","bar"])
>>> you(bar=1,baz=2) == bob(bar=1,baz=2)
False
tl'dr: どうすれば
dict
のキーとして使用することができます。
dict
s?
答えに少し手を加えて、私が使っているより完全な解決策は以下の通りです。 これは、実用的な目的のために、結果のディクストを曖昧に不変にするために少し余分な作業を行うことに注意してください。 もちろん、この問題を回避するために
dict.__setitem__(instance, key, value)
を呼び出すことでハックするのは簡単ですが、私たちは皆大人なのです。
class hashdict(dict):
"""
hashable dict implementation, suitable for use as a key into
other dicts.
>>> h1 = hashdict({"apples": 1, "bananas":2})
>>> h2 = hashdict({"bananas": 3, "mangoes": 5})
>>> h1+h2
hashdict(apples=1, bananas=3, mangoes=5)
>>> d1 = {}
>>> d1[h1] = "salad"
>>> d1[h1]
'salad'
>>> d1[h2]
Traceback (most recent call last):
...
KeyError: hashdict(bananas=3, mangoes=5)
based on answers from
http://stackoverflow.com/questions/1151658/python-hashable-dicts
"""
def __key(self):
return tuple(sorted(self.items()))
def __repr__(self):
return "{0}({1})".format(self.__class__.__name__,
", ".join("{0}={1}".format(
str(i[0]),repr(i[1])) for i in self.__key()))
def __hash__(self):
return hash(self.__key())
def __setitem__(self, key, value):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def __delitem__(self, key):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def clear(self):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def pop(self, *args, **kwargs):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def popitem(self, *args, **kwargs):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def setdefault(self, *args, **kwargs):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
def update(self, *args, **kwargs):
raise TypeError("{0} does not support item assignment"
.format(self.__class__.__name__))
# update is not ok because it mutates the object
# __add__ is ok because it creates a new object
# while the new object is under construction, it's ok to mutate it
def __add__(self, right):
result = hashdict(self)
dict.update(result, right)
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
どのように解決するのですか?
ここでは、ハッシュ化可能な辞書を作る簡単な方法を紹介します。ただ、明らかな理由により、他の辞書に埋め込んだ後、それらを変異させないことを忘れないでください。
class hashabledict(dict):
def __hash__(self):
return hash(tuple(sorted(self.items())))
関連
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] Pythonで2つのリストを連結する方法は?
-
[解決済み] ファイルのコピー方法について教えてください。
-
[解決済み] Pythonで例外を手動で発生(スロー)させる
-
[解決済み] Pythonのdictsで'has_key()'と'in'のどちらを使うべきですか?
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】Pythonに三項条件演算子はありますか?
-
[解決済み] PythonでファイルのMD5チェックサムを計算するには?重複
-
[解決済み] Python 3でバイナリデータを標準出力に書き込むには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】セットへのリスト追加?
-
[解決済み] Pandasのデータフレームでタプルの列を分割するにはどうしたらいいですか?
-
[解決済み] Pythonの構文に新しいステートメントを追加することはできますか?
-
[解決済み] SQLAlchemy: 日付フィールドをフィルタリングする方法は?
-
[解決済み] Pythonのargparseを使った隠し引数の作成
-
[解決済み] python-requests モジュールからのすべてのリクエストをログに記録します。
-
[解決済み] 古いバージョンのPythonにおける辞書のキーの並び順
-
[解決済み] Ctrl-CでPythonスクリプトを終了できない
-
[解決済み] Pythonの文字列書式をリストで使う
-
[解決済み] PythonのRequestsモジュールを使ってWebサイトに "ログイン "するには?