2017-08-03 48 views
-4

我知道,因为像列表这样的不可互相匹配的类型是可变的,所以它们不能用作散列的关键。但是,我不明白为什么他们的内存地址(我不相信更改)可以使用?为什么不能使用不可用类型的内存地址作为字典的关键字?

例如:

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}'不会这样做,因为它会破坏字典的语义。 – user2357112

回答

1

你真的如果扩展listset,可以使用对象作为哈希函数的存储器地址等等

使用存储器地址的主要原因因为如果两个对象相等(a == b评估为True),我们也希望他们的哈希值相等(hash(a) == hash(b)True)。否则,我们可能会收到意想不到的行为。

要看到这样的例子,我们创建自己的类,扩展list并将对象的内存地址用作散列函数。

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

现在我们可以创建两个可哈希列表!我们的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接近彼此在内存中,但不是在同一个位置。由于我们使用内存地址作为我们的哈希值,这也意味着它们的哈希值不相等。

如果比较两个相等元组(或任何其他可哈希对象)的内置哈希,会发生什么?

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

如果你试试这个你自己,你的('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,我们找不到在集a因为hash(b)不等于hash(a),所以我们找不到我们在组等效列表!

相关问题