リストをハッシュするには? 最初にタプルに変換する必要があると言われました。 [1,2,3,4,5]
から(1,2,3,4,5)
。
したがって、最初のものはハッシュできませんが、2番目のものはハッシュできます。なぜ*?
*私は詳細な技術的説明を本当に探しているのではなく、直観を探しています
主に、タプルは不変だからです。次の作品を想定しています:
_>>> l = [1, 2, 3]
>>> t = (1, 2, 3)
>>> x = {l: 'a list', t: 'a Tuple'}
_
さて、l.append(4)
を実行するとどうなりますか?辞書のキーを変更しました!遠くから!ハッシュアルゴリズムがどのように機能するかを熟知している場合、これは恐ろしいはずです。一方、タプルは絶対に不変です。 t += (1,)
はタプルを変更しているように見えるかもしれませんが、実際にはそうではありません。単にnewタプルを作成し、辞書キーを変更しないままにします。
あなたは完全にその作品を作ることができますが、私はあなたが効果を好きではないに違いない。
_from functools import reduce
from operator import xor
class List(list):
def __hash__(self):
return reduce(xor, self)
_
次に、何が起こるか見てみましょう。
_>>> l = List([23,42,99])
>>> hash(l)
94
>>> d = {l: "Hello"}
>>> d[l]
'Hello'
>>> l.append(7)
>>> d
{[23, 42, 99, 7]: 'Hello'}
>>> l
[23, 42, 99, 7]
>>> d[l]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: [23, 42, 99, 7]
_
編集:それで、私はこれについてもう少し考えました。リストのidをハッシュ値として返す場合、上記の例を機能させることができます。
_class List(list):
def __hash__(self):
return id(self)
_
その場合、_d[l]
_は_'Hello'
_を提供しますが、_d[[23,42,99,7]]
_もd[List([23,42,99,7])]
も(新しい_[Ll]ist
_を作成しているため)は提供しません。
リストは変更可能であるため、リストを変更すると、ハッシュも変更されます。これにより、ハッシュ(セットキーやdictキーなど)を持つポイントが失われます。
リストは変更可能であり、タプルは変更できないためです。
すべてのタプルがハッシュ可能というわけではありません。たとえば、タプルには要素としてリストが含まれます。
x = (1,[2,3])
print(type(x))
print(hash(x))