`__eq__`を定義する型はハッシュ化できませんか?
-
05-07-2019 - |
質問
機能をプログラムのPython 3.1フォークに移植するときに、奇妙なバグがありました。次の仮説に絞り込みました。
Python 2.xとは対照的に、Python 3.xでは、オブジェクトに__eq__
メソッドがある場合、自動的にハッシュ化できません。
これは本当ですか?
Python 3.1で起こること:
>>> class O(object):
... def __eq__(self, other):
... return 'whatever'
...
>>> o = O()
>>> d = {o: 0}
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
d = {o: 0}
TypeError: unhashable type: 'O'
次の質問は、個人的な問題をどのように解決すればよいですか?複数のオブジェクトを指すChangeTracker
を格納するオブジェクトWeakKeyDictionary
があり、それぞれに過去の特定の時点でのピクルダンプの値を指定します。既存のオブジェクトがチェックインされるたびに、変更トラッカーは、その新しいピクルが古いピクルと同一であるかどうか、したがってその間にオブジェクトが変更されたかどうかを示します。問題は、指定されたオブジェクトがライブラリ内にあるかどうかをチェックすることさえできないことです。なぜなら、オブジェクトがハッシュできないという例外を発生させるからです。 (これには<=>メソッドがあります。)これを回避するにはどうすればよいですか?
解決
はい、__eq__
を定義すると、デフォルトの__hash__
(つまり、メモリ内のオブジェクトのアドレスのハッシュ)はなくなります。これは重要です。なぜなら、ハッシュは等式と一貫している必要があるからです。等しいオブジェクトは同じハッシュをする必要があります。
ソリューションは簡単です。<=>を定義するだけで<=>を定義するだけです。
他のヒント
http://docs.python.org/3.1のこの段落/reference/datamodel.html#object。ハッシュ
__eq__()
をオーバーライドするクラスの場合 の実装を保持する必要がある__hash__()
親クラスから、インタープリターにこれを伝える必要があります__hash__ = <ParentClass>.__hash__
を設定して明示的に。そうでなければ__hash__
の継承は ブロックされた、まるで<=>があったかのように 明示的にNoneに設定します。
object.__hash__
のPython 3マニュアルを確認してください。 :
クラスが
__eq__()
メソッドを定義しない場合、__hash__()
操作も定義しないでください。__hash__(self)
ではなくid(self)
を定義している場合、そのインスタンスはハッシュ可能なコレクションのアイテムとして使用できません。
エンファシスは私のものです。
怠zyになりたい場合は、x.__hash__()
を定義してid(x)
を返すだけでよいようです:
ユーザー定義クラスには、デフォルトで<=>および<=>メソッドがあります。それらを使用すると、すべてのオブジェクトは等しくない(それ自体を除く)を比較し、<=>は<=>を返します。
私はpythonの専門家ではありませんが、eqメソッドを定義するときは、(メソッドのハッシュ値を計算する)hashメソッドも定義する必要があることは意味がありません。ハッシュメカニズムは、同じオブジェクトにヒットしたか、同じハッシュ値を持つ別のオブジェクトにヒットしたかを知りません。実際、それは逆です。おそらく、あなたの__eq__
メソッドで等しいと見なされるオブジェクトに対して異なるハッシュ値を計算することになります。
そのハッシュ関数が何と呼ばれているのかわかりませんが、__hash__
? :)