为什么我不能将列表用作字典键?

时间:2014-05-09 06:22:40

标签: python list dictionary hash

为什么我不能将列表用作字典键?

hlst是一个列表。 备忘录是一个词典。

if not hlst in memo:
    # do something
else:
    configurations = memo[hlst]

当我尝试它时,python告诉我hlist是不可用的。

2 个答案:

答案 0 :(得分:1)

你的问题是缺乏对#34; hashable"概念

如果你能够为它计算哈希码,我们称object" hashable&#34 ;.

Hashcode(a.k.a。哈希函数)是一个函数,它接受对象并返回一些值,USUALLY应该足以将它与其他对象区分开来。这意味着,某些点的哈希码应该可以用作ID。当然,会出现所谓的"哈希冲突" (当两个对象具有相同的哈希码时),因为有更多可能的对象而不是哈希码。

对于散列函数(用于获取对象的haschode的函数)而言,更重要的是(而不是#34;不同的对象具有不同的散列码")约束,它在对象的整个生命周期中应该是相同的。 / p>

看:我们有对象a,它们具有属性/属性xy。要使哈希函数正常工作,您需要确保,哈希值不依赖于xy

列表具有依赖于其值哈希码的哈希码,因此它们本身是不可用的。为什么?因为如果更改列表的一个元素(或添加一个,或删除等),其哈希码会更改(因为它取决于此元素)。

现在,回到字典。 Dictionary是一个哈希表,可以描述为"简单的内存中对数组,在索引(X modulo(数组大小))下有值,第一项有哈希码X" (这是一个非常简化,但主要概念贯穿语言和实现;对的第一个值称为"键",第二个"值"或"项目&#34 )。如果要将列表[A,B]与哈希码1234和值V一起插入到大小为10的哈希表中,然后将此列表的值更改为[A,C](这意味着将haschode更改为5678),则在插入对的时刻([A,B],V)将以指数1234模10 = 4进行,但在改变之后它应该在指数5678模10 = 8。

为了使其正常工作,我们需要在每次密钥对象发生变化时通知哈希表(这很难实现,难以实现,并且占用大量资源),或者确保密钥的哈希码赢了&# 39; t改变,就像在哈希表中一样。 Python创建者选择了第二种选择,因为它被广泛使用,证明效果很好并且稳定。

这是python有两个有序集合类型的原因之一 - 列表和元组。您可能知道,元组是不可变的,因此它的哈希码不会改变 - 它可以用作字典键。

PS。上面的文字非常简单。列表哈希码对其元素的依赖性有点棘手。此外,字典作为hashmap的实现没有在语言参考中定义 - 它只表示键应该是可以清除的,并不能解释原因。某些实现可以很好地处理不可用的对象,但是为了符合引用,强制使用hashable键。

答案 1 :(得分:0)

您不能将列表用作键,因为列表是可变的。因为它们是可变的,所以它们不能是可以清洗的(如字符串和元组)。假设hlist = ['a']。想想如果您将hlist的内容更改为['b']会发生什么。 memo[['a']]会返回什么?

为了解决这个问题,您可以根据blackryder的评论将列表转换为元组tuple(hlist)