2017-08-03 1 views
-4

私は、リストのような解けない型は突然変異しているので、ハッシュの鍵として使うことはできないことを理解しています。しかし、私はなぜ彼らのメモリアドレス(私は変更を信じていない)が使用できるのか分からない。例えばDictのキーとして、非ハッシュタイプのメモリアドレスを使用できないのはなぜですか?

my_list = [1,2,3] 
my_dict = {my_list: 1} #error 
my_dict = {id(my_list): 1} # no error 
+0

これらはディクテーションではありません。プラス 'id()'は 'int'を返すので、なぜ動作しないのでしょうか? –

+1

整数をハッシングしています。 –

+1

簡単にはできますが、 '{some_list:whatever} 'はそれをしません。なぜなら、それはdictsのセマンティクスを壊すからです。 – user2357112

答えて

1

あなた実際あなたがlistを拡張する場合など、set、ハッシュ関数のようなオブジェクトのメモリアドレスを使用することができます

メモリアドレスを使用して第一の理由2つのオブジェクトが等しい場合(a == bTrueと評価されるため)、ハッシュ値が同じである(hash(a) == hash(b)True)ようにしたいからです。さもなければ、意図しない振る舞いをする可能性があります。

この例を見るには、listを拡張する独自のクラスを作成し、そのオブジェクトのメモリアドレスをハッシュ関数として使用しましょう。

>>> class HashableList(list): 
     def __hash__(self): 
      return id(self) # Returns the memory address of the object 

ここで、2つのハッシュ可能リストを作成できます。私たちのHashableListは、pythonのビルトインリストと同じコンストラクタを使います。

>>> a = HashableList((1, 2, 3)) 
>>> b = HashableList((1, 2, 3)) 

案の定、私たちが期待するように、我々は

>>> a == b 
True 

を取得し、我々は我々のリストをハッシュすることができます!

>>> hash(a) 
1728723187976 
>>> hash(b) 
1728723187816 
>>> hash(a) == hash(b) 
False 

あなたは最後の3桁の数字を見れば、あなたが表示されますabは、メモリ内の互いに近接しているが、同じ場所にはありません。我々はハッシュとしてメモリアドレスを使用しているので、ハッシュ値が等しくないことも意味します。

2つの等しいタプル(または他のハッシュ可能オブジェクト)の組み込みハッシュを比較するとどうなりますか?

>>> y = ('foo', 'bar') 
>>> z = ('foo', 'bar') 
>>> y == z 
True 
>>> hash(y) 
-1256824942587948134 
>>> hash(z) 
-1256824942587948134 
>>> hash(y) == hash(z) 
True 

あなた自身でこれをしようとすると、文字列のハッシュは毎回のpythonが始まるの新しいセッションを変更するので、('foo', 'bar')のあなたのハッシュは、地雷とは一致しません。重要なことは、同じセッションでhash(y)は常にhash(z)と等しいことです。

私たちがセットを作って、HashableListのオブジェクトと作ったタプルで遊んでみましょう。

>>> s = set() 
>>> s.add(a) 
>>> s.add(y) 
>>> s 
{[1, 2, 3], ('foo', 'bar')} 

>>> a in s # Since hash(a) == hash(a), we can find a in our set 
True 
>>> y in s # Since hash(y) == hash(y), we can find y in our set 
True 
>>> b in s 
False 
>>> z in s 
True 

でもa == bかかわらず、hash(b)が等しいhash(a)ないので、我々はセットでaを見つけることができなかったので、我々はセットで私たちの同等のリストを見つけることができませんでした!

関連する問題