プログラムの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__
メソッドがあるためです。)これを回避するにはどうすればよいですか?
はい、__eq__
を定義すると、デフォルトの__hash__
(つまり、メモリ内のオブジェクトのアドレスをハッシュする)はなくなります。ハッシュは同等性と一致している必要があるため、これは重要です。同等のオブジェクトは同じものをハッシュする必要があります。
解決策は簡単です。__hash__
を定義するとともに__eq__
を定義するだけです。
http://docs.python.org/3.1/reference/datamodel.html#object。hash からのこの段落
__eq__()
をオーバーライドするクラスが親クラスからの__hash__()
の実装を保持する必要がある場合、インタプリタは___hash__ = <ParentClass>.__hash__
_を設定することによってこれを明示的に通知する必要があります。そうしないと、___hash__
_が明示的にNoneに設定されているかのように、__hash__()
の継承がブロックされます。
Python 3マニュアル _object.__hash__
_ :
クラスが
__eq__()
メソッドを定義しない場合は、__hash__()
操作も定義しないでください。__eq__()
を定義しているが__hash__()
を定義していない場合、そのインスタンスはハッシュ可能なコレクションのアイテムとして使用できません。
強調は私のものです。
怠惰になりたい場合は、__hash__(self)
を定義してid(self)
を返すことができるようです。
ユーザー定義クラスには、デフォルトで
__eq__()
メソッドと__hash__()
メソッドがあります。それらを使用すると、すべてのオブジェクトが等しくなく(自分自身を除く)比較され、x.__hash__()
はid(x)
を返します。
私はpythonエキスパートではありませんが、eq-methodを定義するときに、ハッシュメソッド(ハッシュ値を計算する)も定義する必要があることは意味がありません。オブジェクトの場合)そうでない場合、ハッシュメカニズムは、同じオブジェクトにヒットしたのか、同じハッシュ値を持つ別のオブジェクトにヒットしたのかを認識しません。実際には、その逆で、おそらく異なるハッシュ値を計算することになります。 __eq__
メソッドによって等しいと見なされたオブジェクトの場合。
そのハッシュ関数が何と呼ばれているのかわかりませんが、__hash__
でしょうか? :)