我知道,因为像列表这样的不可互相匹配的类型是可变的,所以它们不能用作散列的关键。但是,我不明白为什么他们的内存地址(我不相信更改)可以使用?为什么不能使用不可用类型的内存地址作为字典的关键字?
例如:
my_list = [1,2,3]
my_dict = {my_list: 1} #error
my_dict = {id(my_list): 1} # no error
我知道,因为像列表这样的不可互相匹配的类型是可变的,所以它们不能用作散列的关键。但是,我不明白为什么他们的内存地址(我不相信更改)可以使用?为什么不能使用不可用类型的内存地址作为字典的关键字?
例如:
my_list = [1,2,3]
my_dict = {my_list: 1} #error
my_dict = {id(my_list): 1} # no error
你真的如果扩展list
,set
,可以使用对象作为哈希函数的存储器地址等等
使用存储器地址的主要原因因为如果两个对象相等(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个数字,你会看到a
和b
接近彼此在内存中,但不是在同一个位置。由于我们使用内存地址作为我们的哈希值,这也意味着它们的哈希值不相等。
如果比较两个相等元组(或任何其他可哈希对象)的内置哈希,会发生什么?
>>> 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)
,所以我们找不到我们在组等效列表!
那些套不是字典。加'id()'返回一个'int'为什么它不工作? –
你正在整理一个整数。 –
你*很容易,但'{some_list:whatever}'不会这样做,因为它会破坏字典的语义。 – user2357112