Python 为什么我不能使用列表作为字典键?
为什么我不能使用列表作为字典键 hlst是一个列表。 备忘录是一份口述Python 为什么我不能使用列表作为字典键?,python,list,dictionary,hash,Python,List,Dictionary,Hash,为什么我不能使用列表作为字典键 hlst是一个列表。 备忘录是一份口述 if not hlst in memo: # do something else: configurations = memo[hlst] 当我尝试它时,python告诉我hlist是不可损坏的 不能将列表用作键,因为列表是可变的。因为它们是可变的,所以它们不能是可散列的(就像字符串和元组一样)。假设hlist=['a']。想想如果将hlist的内容更改为['b'],会发生什么情况。memo[['a']]会
if not hlst in memo:
# do something
else:
configurations = memo[hlst]
当我尝试它时,python告诉我hlist是不可损坏的 不能将列表用作键,因为列表是可变的。因为它们是可变的,所以它们不能是可散列的(就像字符串和元组一样)。假设
hlist=['a']
。想想如果将hlist
的内容更改为['b']
,会发生什么情况。memo[['a']]
会返回什么
要克服这个问题,您可以按照darkryder的评论,将列表转换为一个元组
元组(hlist)
。您的问题是缺乏对“哈希”概念的理解
如果您能够计算对象的hashcode,我们将其称为“hashable”
Hashcode(又称hash函数)是一个函数,它接受对象并返回一些值,这些值通常足以将其与其他对象区分开来。这意味着,hashcode在某种程度上应该可用作ID。当然,会有所谓的“hash冲突”(当两个对象具有相同的hashcode时),因为可能的对象比hashcode多得多
对散列函数(用于获取对象的haschode的函数)的约束(比“不同的对象有不同的hashcode”)更重要的是,在对象的整个生命周期中,它应该是相同的
看:我们有一个对象a
,它有属性/属性x
和y
。为了使散列函数正常工作,您需要确保a的散列不依赖于x
和y
列表的hashcode依赖于其值hashcodes,因此它们本身是不可损坏的。为什么?因为如果您更改列表中的一个元素(或添加一个,或删除一个,等等),它的哈希代码会更改(因为它依赖于这个元素)
现在,回到字典。字典是一个哈希表,可以描述为“简单的内存对数组,索引(X模(数组大小))下有值,第一项有哈希代码X”(这是一个相当简单的概念,但主要概念贯穿语言和实现;对的第一个值称为“键”,第二个值称为“值”,或“项”)。如果要将哈希代码为1234、值为V的列表[A,B]插入到大小为10的哈希表中,然后将该列表的值更改为[A,C](这意味着将haschode更改为5678),则在插入对时([A,B],V)将位于索引1234模10=4处,但更改后应位于索引5678模10=8处
为了使其正常工作,我们需要在每次键对象更改时通知哈希表(这很难看,很难实现,并且占用了很多资源),或者确保键的哈希代码不会像哈希表中的哈希代码那样长时间更改。Python创建者选择了第二个选项,因为它被广泛使用,被证明工作良好且稳定
这就是python有两种有序集合类型的原因之一——列表和元组。正如您可能知道的,元组是不可变的,因此其哈希代码不应更改-因此,它可以用作字典键
注:上面的文字相当简单。列表哈希代码对其元素的依赖性有点棘手。另外,字典作为hashmap的实现并没有在语言引用中定义——它只是说键应该是可散列的,并没有解释为什么。有些实现可以很好地处理不可破坏的对象,但为了符合引用,可以强制使用哈希键。不知道您在问什么。你的问题不清楚。如果
hlst
是一个列表,那么它不可能在字典中。那你为什么要检查?(如果要将列表添加到字典中,请先将其转换为元组,使用tuple(hlst)
:只需确保在将任何其他值用作键或检查其存在性之前,始终将其转换为元组)如果这是您的意思,则不能附加dict。也许你想在列表中添加一个dict?这实际上是一个好问题。我重新制定了它,使它更清楚。不能将列表用作键,因为列表是可变的。因为它们是可变的,所以它们不能是可散列的(就像字符串和元组一样)。假设hlist=['a']
。想想如果您将hlist的内容更改为['b'],会发生什么情况。memo[[a']
会返回什么?列表是可变的。字典要求键是不可变的,以便键(因此键的散列)保持不变。将其转换为元组或字符串表示形式。或者,如果列表很大,请尝试其他实现。检查问题是,它实际上可能是一个包含列表列表的元组。如何转换所有级别?此外,常规类的实例是可散列的,您也可以对它们进行变异。