ユーザー定義クラスのデフォルトのハッシュは、IDを返すだけです。これにより、多くの場合役立つ動作が得られます。ユーザー定義クラスのインスタンスをディクショナリキーとして使用すると、値を検索するためにまったく同じオブジェクトが再度提供されたときに、関連付けられた値を取得できます。例えば:
>>> class Foo(object):
def __init__(self, foo):
self.foo = foo
>>> f = Foo(10)
>>> d = {f: 10}
>>> d[f]
10
これは、ユーザー定義クラスのデフォルトの同等性と一致します。
>>> g = Foo(10)
>>> f == g
False
>>> d[g]
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
d[g]
KeyError: <__main__.Foo object at 0x0000000002D69390>
f
とg
の属性の値が同じであっても、それらは等しくなく、で検索g
しd
ても、の下に格納されている値が見つからないことに注意してくださいf
。さらに、の値を変更しても、をf.foo
検索f
するd
と次の値が見つかります。
>>> f.foo = 11
>>> d[f]
10
プログラマーがとを定義することによって2つのインスタンスが同等として扱われるための条件を明確に宣言しない限り、任意の新しいクラスのインスタンスは非同等として扱われるべきであるという前提があり__eq__
ます__hash__
。
そして、これはほとんど機能します。クラスを定義する場合Car
、おそらく、同じ属性を持つ2台の車が2台の異なる車を表していると見なします。車を登録所有者にマッピングする辞書を持っている場合、アリスとボブが同じ車を所有している場合でも、ボブの車を検索するときにアリスを見つけたくありません。OTOH、郵便番号を表すクラスを定義する場合、同じコードを持つ2つの異なるオブジェクトを「同じ」ものの交換可能な表現と見なしたいと思うでしょう。この場合、郵便番号を州にマッピングする辞書があれば、同じ郵便番号を表す2つの異なるオブジェクトで同じ状態を見つけられるようにしたいと思います。
これを「値型」と「オブジェクト型」の違いと呼んでいます。値型はある値を表します。それは私が気にする値であり、個々のオブジェクトのIDではありません。同じ値を考え出す2つの異なる方法は同じように優れており、値型を渡すコードの「コントラクト」は通常、特定のオブジェクトを指定せずに、何らかの値を持つオブジェクトを提供することを約束します。オブジェクトタイプOTOHの場合、別のインスタンスとまったく同じデータが含まれている場合でも、個々のインスタンスには独自のIDがあります。オブジェクトタイプを渡すコードの「コントラクト」は、通常、正確な個々のオブジェクトを追跡することを約束します。
では、組み込みの可変クラスがIDをハッシュとして使用しないのはなぜですか?これは、それらがすべてコンテナーであるためです。通常、コンテナーは値型に似ていると見なされ、その値は含まれている要素によって決定されます。
>>> [1, 2, 3] == [1, 2, 3]
True
>>> {f: 10} == {f: 10}
True
ただし、可変コンテナの値は一時的です。一部の特定のリストには現在値がありますが、値[1, 2, 3]
をに変更することができます[4, 5, 6]
。リストを辞書キーとして使用できる場合は、ルックアップでリストの(現在の)値を使用するか、そのIDを使用するかを決定する必要があります。いずれにせよ、現在辞書キーとして使用されているオブジェクトの値が変更されて変更された場合、(非常に)驚かされる可能性があります。オブジェクトを辞書キーとして使用することは、オブジェクトの値がそのIDである場合、またはオブジェクトのIDがその値と無関係である場合にのみうまく機能します。したがって、Pythonが選択した答えは、可変コンテナをハッシュ不可と宣言することです。
さて、あなたの直接の質問に答えるためのより具体的な詳細:
1)CPythonのこのデフォルトハッシュ(他の回答/コメントによると明らかに<2.6のみ)はオブジェクトのメモリアドレスにマップされるため、CPythonでは、両方が同時にライブであるデフォルトハッシュを使用する2つのオブジェクトが衝突する可能性はありません関係するクラスに関係なく、ハッシュ値(および、辞書キーとして格納されている場合はライブ)。また、ハッシュとしてメモリアドレスを使用しない他のPython実装では、デフォルトのハッシュを使用してオブジェクト間で細かいハッシュ分散を行う必要があることも期待します。そうです、あなたはそれに頼ることができます。
2)カスタムハッシュとして、既存のオブジェクトのハッシュとまったく同じ結果を返さない限り、比較的問題はありません。私の理解では、Pythonのハッシュベースのコンテナーは、完全に縮退していない限り、次善のハッシュ関数に対して比較的寛容です。