为什么我不能在python中使用列表作为字典键?

我有点困惑什么可以/不能用作python字典的关键。

dicked = {} dicked[None] = 'foo' # None ok dicked[(1,3)] = 'baz' # tuple ok import sys dicked[sys] = 'bar' # wow, even a module is ok ! dicked[(1,[3])] = 'qux' # oops, not allowed 

所以一个元组是一个不可变的types,但如果我隐藏一个列表里面,那么它不能成为一个键..我不能像在一个模块内轻松隐藏列表?

我有一个模糊的想法,认为关键必须是“可排除的”,但我只是承认我对技术细节的无知。 我不知道这里发生了什么事。 如果你试图使用列表作为关键字,将散列称为内存位置,会出现什么问题?

关于Python维基上的主题有一篇很好的文章: 为什么列表不能成为字典键 。 如上所述:

如果你试图使用列表作为关键字,将散列称为内存位置,会出现什么问题?

这可以在没有真正违反任何要求的情况下完成,但会导致意想不到的行为。 通常将列表视为就像它们的值是从其内容的值中派生出来的一样,例如在检查(相等)时。 许多人会 – 可以理解 – 希望你可以使用任何列表[1, 2]获得相同的密钥,你必须保持完全相同的列表对象。 但是,一旦用作键的列表被修改,通过值查找就会中断查找,并且通过身份查找需要保持完全相同的列表 – 这对于任何其他常用列表操作都是不需要的(至less没有我能想到的)。

其他的对象,比如模块和object ,无论如何都会使对象的身份发生更大的变化(何时是最后一次有两个不同的模块对象叫做sys ?),然后再进行比较。 因此,在这种情况下,它们作为字典键时,通过身份进行比较也就不那么令人惊讶了,甚至没有预料到。

为什么我不能在python中使用列表作为字典键?

 >>> d = {repr([1,2,3]): 'value'} {'[1, 2, 3]': 'value'} 

(对于任何在这个问题上磕磕绊绊寻找解决方法的人)

正如这里的其他人所解释的,事实上你不能。 你可以使用它的string表示来代替,如果你真的想使用你的列表。

问题是元组是不可变的,列表不是。 考虑以下

 d = {} li = [1,2,3] d[li] = 5 li.append(4) 

应该返回什么? 这是同一个列表吗? 怎么样d[[1,2,3]] ? 它有相同的值,但是是不同的列表?

最终,没有令人满意的答案。 例如,如果唯一有效的密钥是原始密钥,那么如果您没有对该密钥的引用,则永远不能再访问该值。 与其他每个允许的密钥,您可以构build一个没有参考原始的密钥。

如果我的两个build议都起作用,那么你有非常不同的键返回相同的值,这是有点令人惊讶。 如果只有原始内容工作,那么你的密钥会很快变坏,因为列表被修改。

这是一个答案http://wiki.python.org/moin/DictionaryKeys

如果你试图使用列表作为关键字,将散列称为内存位置,会出现什么问题?

查找具有相同内容的不同列表将产生不同的结果,即使比较具有相同内容的列表将表明它们是等同的。

怎么样在字典查找中使用列表文字?

你的awnser可以在这里find:

为什么列表不能是字典键

Python新手经常想知道为什么,虽然语言包括一个元组和一个列表types,元组可以用作字典键,而列表不是。 这是一个深思熟虑的devise决定,可以通过首先了解Python字典是如何工作来解释。

源和更多信息: http : //wiki.python.org/moin/DictionaryKeys

对你的问题的简单回答是,类列表没有实现方法散列所需的任何对象,希望被用作在字典中的键。 然而, 哈希没有以同样的方式实现的原因是因为元组类(基于容器的内容)是因为列表是可变的,所以编辑列表将需要重新计算哈希,这可能意味着列performance在位于下面的哈希表内的错误的桶中。 请注意,由于您无法修改元组(不可变),因此不会遇到此问题。

作为一个侧面说明,dictobjects lookup的实际实现是基于Knuth Vol。 3,Sec。 6.4。 如果你有这本书对你来说可能是一个值得阅读,另外如果你真的真正感兴趣,你可能喜欢在开发人员对dictobject的实际执行情况的意见在这里偷看。 它详细说明了它的工作原理。 还有一个关于你可能感兴趣的字典实现的python讲座 。他们通过一个关键字的定义,以及在最初的几分钟里是一个什么样的hash。

根据Python 2.7.2文档:

如果一个对象具有一个在其生命周期中从不改变的散列值(它需要一个hash ()方法),并且可以与其他对象进行比较(它需要一个eq ()或cmp ()方法),则该对象是可散列的。 比较相等的哈希对象必须具有相同的哈希值。

Hashability使对象可用作字典键和集合成员,因为这些数据结构在内部使用散列值。

所有Python的不可变内置对象都是可散列的,而没有可变容器(如列表或字典)。 对象是用户定义的类的实例默认可哈希; 他们都比较不等,他们的哈希值是他们的id()。

一个元组是不可改变的,你不能添加,删除或replace它的元素,但元素本身可能是可变的。 列表的散列值取决于其元素的散列值,因此当您更改元素时,散列值会发生变化。

使用id作为列表散列意味着所有列表的比较不同,这将是令人惊讶和不便的。

Interesting Posts