Python 为什么可以';你不能用一个不易损坏的内存地址作为dict的键吗?
我知道,由于列表等不可破坏的类型正在变异,它们不能用作散列的键。然而,我不明白为什么他们的内存地址(我不相信会有变化)可以使用 例如:Python 为什么可以';你不能用一个不易损坏的内存地址作为dict的键吗?,python,python-2.7,python-3.x,Python,Python 2.7,Python 3.x,我知道,由于列表等不可破坏的类型正在变异,它们不能用作散列的键。然而,我不明白为什么他们的内存地址(我不相信会有变化)可以使用 例如: my_list = [1,2,3] my_dict = {my_list: 1} #error my_dict = {id(my_list): 1} # no error 如果扩展列表、集等,实际上可以将对象的内存地址用作哈希函数 使用内存地址进行哈希的主要原因是,如果两个对象相等(a==b的计算结果为True),我们也希望它们的哈希相等(hash(a)==h
my_list = [1,2,3]
my_dict = {my_list: 1} #error
my_dict = {id(my_list): 1} # no error
如果扩展列表
、集
等,实际上可以将对象的内存地址用作哈希函数
使用内存地址进行哈希的主要原因是,如果两个对象相等(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
在内存中彼此靠近,但不在同一位置。因为我们使用内存地址作为散列,这也意味着它们的散列不相等
如果比较两个相等元组(或任何其他可哈希对象)的内置哈希,会发生什么
如果您自己尝试,您的('foo','bar')
哈希值将与我的不匹配,因为每次启动新的python会话时,字符串哈希值都会发生变化。重要的是,在同一会话中,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)
,所以我们无法在集合中找到等价的列表 那些是布景,不是口述。Plusid()
返回一个int
那么为什么它不起作用呢?你正在对一个整数进行散列运算。你可以,很容易,但是{some\u list:which}
不会这样做,因为它会破坏dicts的语义。
>>> 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