2024-09-26 22:54:06 发布
网友
为什么我不能用列表作为字典的关键字?在
hlst是一个列表。 备忘录是口述
if not hlst in memo: # do something else: configurations = memo[hlst]
当我尝试时,python告诉我hlist是不可更改的。在
你的问题是缺乏对“散列”概念的不理解。在
如果你能计算出对象的hashcode,我们称之为“hashable”。在
Hashcode(又称hash函数)是一个接受对象并返回一些值的函数,这些值通常足以将它与其他对象区分开来。这意味着,hashcode在某种程度上应该可以作为ID使用,当然,会出现所谓的“hash conflicts”(当两个对象具有相同的hashcode时),因为可能的对象比hashcode多得多。在
对散列函数(用于获取对象haschode的函数)的约束(比“不同的对象有不同的hashcode”)更重要的是,它在对象的整个生命周期中应该是相同的。在
看:我们有对象a,它有属性/属性x和{}。要使散列函数正常工作,您需要确保a的散列不依赖于x和{}。在
a
x
列表的hashcode依赖于其值hashcode,因此它们本身是不可损坏的。为什么?因为如果你改变了list的一个元素(或者add,remove,等等),它的hashcode也会改变(因为它依赖于这个元素)。在
现在,回到字典。Dictionary是一个散列表,可以描述为“在内存中简单的成对数组,在索引(X modulo(array size))下有值,其中第一个项有hashode X”(这是一个相当简单的方法,但主要概念贯穿语言和实现;对的第一个值称为“key”,第二个“value”或“item”)。如果要将哈希码为1234且值为V的列表[A,B]插入到大小为10的哈希表中,然后将该列表的值更改为[A,C](这意味着haschode更改为5678),则在插入对时([A,B],V)将在索引1234模10=4处执行,但更改后应位于索引5678模10=8处。在
为了使其正常工作,我们需要在每次key对象发生变化时通知hash table(这很难看,很难实现,并且占用大量资源),或者确保key的hashcode不会像hash table中那样长时间地更改。Python的创建者选择了第二种选择,因为它被广泛使用,并且被证明工作良好且稳定。在
这就是python有两种有序集合类型的原因之一——列表和元组。正如您可能知道的,元组是不可变的,所以它的哈希代码不应该更改-因此,它可以用作字典键。在
以上文字相当简单。列表哈希代码对其元素的依赖性有点棘手。另外,dictionary作为hashmap的实现并没有在语言引用中定义——它只说明键应该是散列的,并没有解释为什么。有些实现可以很好地处理不易损坏的对象,但是为了符合引用,强制使用散列键。在
不能将列表用作键,因为列表是可变的。因为它们是可变的,所以它们不能是散列的(比如字符串和元组)。假设hlist = ['a']。想想如果您将hlist的内容更改为['b'],会发生什么。memo[['a']]会返回什么?在
hlist = ['a']
hlist
['b']
memo[['a']]
为了克服这个问题,您可以根据darkryder的评论将列表转换为一个元组tuple(hlist)。在
tuple(hlist)
你的问题是缺乏对“散列”概念的不理解。在
如果你能计算出对象的hashcode,我们称之为“hashable”。在
Hashcode(又称hash函数)是一个接受对象并返回一些值的函数,这些值通常足以将它与其他对象区分开来。这意味着,hashcode在某种程度上应该可以作为ID使用,当然,会出现所谓的“hash conflicts”(当两个对象具有相同的hashcode时),因为可能的对象比hashcode多得多。在
对散列函数(用于获取对象haschode的函数)的约束(比“不同的对象有不同的hashcode”)更重要的是,它在对象的整个生命周期中应该是相同的。在
看:我们有对象}。要使散列函数正常工作,您需要确保a的散列不依赖于}。在
a
,它有属性/属性x
和{x
和{列表的hashcode依赖于其值hashcode,因此它们本身是不可损坏的。为什么?因为如果你改变了list的一个元素(或者add,remove,等等),它的hashcode也会改变(因为它依赖于这个元素)。在
现在,回到字典。Dictionary是一个散列表,可以描述为“在内存中简单的成对数组,在索引(X modulo(array size))下有值,其中第一个项有hashode X”(这是一个相当简单的方法,但主要概念贯穿语言和实现;对的第一个值称为“key”,第二个“value”或“item”)。如果要将哈希码为1234且值为V的列表[A,B]插入到大小为10的哈希表中,然后将该列表的值更改为[A,C](这意味着haschode更改为5678),则在插入对时([A,B],V)将在索引1234模10=4处执行,但更改后应位于索引5678模10=8处。在
为了使其正常工作,我们需要在每次key对象发生变化时通知hash table(这很难看,很难实现,并且占用大量资源),或者确保key的hashcode不会像hash table中那样长时间地更改。Python的创建者选择了第二种选择,因为它被广泛使用,并且被证明工作良好且稳定。在
这就是python有两种有序集合类型的原因之一——列表和元组。正如您可能知道的,元组是不可变的,所以它的哈希代码不应该更改-因此,它可以用作字典键。在
以上文字相当简单。列表哈希代码对其元素的依赖性有点棘手。另外,dictionary作为hashmap的实现并没有在语言引用中定义——它只说明键应该是散列的,并没有解释为什么。有些实现可以很好地处理不易损坏的对象,但是为了符合引用,强制使用散列键。在
不能将列表用作键,因为列表是可变的。因为它们是可变的,所以它们不能是散列的(比如字符串和元组)。假设
hlist = ['a']
。想想如果您将hlist
的内容更改为['b']
,会发生什么。memo[['a']]
会返回什么?在为了克服这个问题,您可以根据darkryder的评论将列表转换为一个元组
tuple(hlist)
。在相关问题 更多 >
编程相关推荐