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

时间:2021-06-17 06:53:37

I'm a bit confused about what can/can't be used as a key for a python dict.

我有点搞不懂什么是可以/不能用作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

So a tuple is an immutable type but if I hide a list inside of it, then it can't be a key.. couldn't I just as easily hide a list inside a module?

所以一个元组是一个不可变类型,但是如果我在它里面隐藏一个列表,那么它就不可能是一个键。难道我就不能简单地把一个列表隐藏在模块中吗?

I had some vague idea that that the key has to be "hashable" but I'm just going to admit my own ignorance about the technical details; I don't know what's really going on here. What would go wrong if you tried to use lists as keys, with the hash as, say, their memory location?

我有一个模糊的想法,那就是钥匙必须是“可洗的”,但我只是承认我自己对技术细节的无知;我不知道这里到底发生了什么。如果您试图使用列表作为键,而使用散列,比如,它们的内存位置,那么会出现什么问题呢?

7 个解决方案

#1


21  

There's a good article on the topic in the Python wiki: Why Lists Can't Be Dictionary Keys. As explained there:

在Python wiki中有一篇关于这个主题的好文章:为什么列表不能是字典密钥。作为解释:

What would go wrong if you tried to use lists as keys, with the hash as, say, their memory location?

如果您试图使用列表作为键,而使用散列,比如,它们的内存位置,那么会出现什么问题呢?

It can be done without really breaking any of the requirements, but it leads to unexpected behavior. Lists are generally treated as if their value was derived from their content's values, for instance when checking (in-)equality. Many would - understandably - expect that you can use any list [1, 2] to get the same key, where you'd have to keep around exactly the same list object. But lookup by value breaks as soon as a list used as key is modified, and for lookup by identity requires you to keep around exactly the same list - which isn't requires for any other common list operation (at least none I can think of).

它可以在不破坏任何需求的情况下完成,但它会导致意外的行为。列表通常被视为从其内容的值中派生出它们的值,例如在检查(in-)相等时。可以理解的是,许多人希望您可以使用任何列表[1,2]来获得相同的密钥,在那里您必须保留完全相同的列表对象。但是,当一个列表作为键被修改时,查找值就会中断,而为了查找,需要您保留完全相同的列表——这并不需要任何其他常见的列表操作(至少我能想到的)。

Other objects such as modules and object make a much bigger deal out of their object identity anyway (when was the last time you had two distinct module objects called sys?), and are compared by that anyway. Therefore, it's less surprising - or even expected - that they, when used as dict keys, compare by identity in that case as well.

其他的对象,比如模块和对象,无论如何都能从它们的对象标识中获得更大的好处(上次您有两个不同的模块对象,称为sys?),并将它们进行比较。因此,当被用作字典的关键字时,它们的身份也就不那么令人惊讶了,甚至是意料之中的。

#2


16  

Why can't I use a list as a dict key in python?

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

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

(for anybody who stumbles on this question looking for a way around it)

(对于任何在这个问题上有问题的人来说,寻找解决办法)

as explained by others here, indeed you cannot. You can however use its string representation instead if you really want to use your list.

正如这里的其他人所解释的那样,你确实不能。但是,如果你真的想使用你的列表,你可以使用它的字符串表示。

#3


9  

The issue is that tuples are immutable, and lists are not. Consider the following

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

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

What should d[li] return? Is it the same list? How about d[[1,2,3]]? It has the same values, but is a different list?

d(李)返回什么?是同一个列表吗?如何d[[1,2,3]]?它有相同的值,但是是不同的列表吗?

Ultimately, there is no satisfactory answer. For example, if the only key that works is the original key, then if you have no reference to that key, you can never again access the value. With every other allowed key, you can construct a key without a reference to the original.

最终,没有令人满意的答案。例如,如果唯一有效的键是原来的键,那么如果没有对该键的引用,就再也无法访问该值。使用所有其他允许的键,您可以构造一个关键字,而不需要引用原始。

If both of my suggestions work, then you have very different keys that return the same value, which is more than a little surprising. If only the original contents work, then your key will quickly go bad, since lists are made to be modified.

如果我的两个建议都有效,那么返回相同值的键就会非常不同,这就有点让人吃惊了。如果原来的内容是有效的,那么你的密钥就会很快变坏,因为列表是要修改的。

#4


7  

Here's an answer http://wiki.python.org/moin/DictionaryKeys

这里有一个回答http://wiki.python.org/moin/DictionaryKeys

What would go wrong if you tried to use lists as keys, with the hash as, say, their memory location?

如果您试图使用列表作为键,而使用散列,比如,它们的内存位置,那么会出现什么问题呢?

Looking up different lists with the same contents would produce different results, even though comparing lists with the same contents would indicate them as equivalent.

用相同的内容查找不同的列表会产生不同的结果,即使将列表与相同的内容进行比较也会表明它们是等价的。

What about Using a list literal in a dictionary lookup?

如何在字典查找中使用列表文字?

#5


2  

Your awnser can be found here:

你的awnser可以在这里找到:

Why Lists Can't Be Dictionary Keys

为什么列表不能是字典键?

Newcomers to Python often wonder why, while the language includes both a tuple and a list type, tuples are usable as a dictionary keys, while lists are not. This was a deliberate design decision, and can best be explained by first understanding how Python dictionaries work.

Python的新手常常想知道为什么,虽然语言既包括元组,也包括列表类型,元组可以用作字典键,而列表则不是。这是一个经过深思熟虑的设计决策,最好先理解Python字典是如何工作的。

Source & more info: http://wiki.python.org/moin/DictionaryKeys

来源&更多信息:http://wiki.python.org/moin/DictionaryKeys。

#6


0  

The simple answer to your question is that the class list does not implement the method hash which is required for any object which wishes to be used in as a key in a dictionary. However the reason why hash is not implemented the same way it is in say the tuple class (based on the content of the container) is because a list is mutable so editing the list would require the hash to be recalculated which may mean the list in now located in the wrong bucket within the underling hash table. Note that since you cannot modify a tuple (immutable) it doesn't run into this problem.

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

As a side note the actual implementation of the dictobjects lookup is based on Algorithm D from Knuth Vol. 3, Sec. 6.4. If you have that book available to you it might be a worthwhile read, in addition if your really really interested you may like to take a peek at the developer comments on the actual implementation of dictobject here. It goes into great detail as to exactly how it works. There is also a python lecture on the implementation of dictionaries which you may be interested in. They go through the definition of a key and what a hash is in the first few minutes.

另外,dictobjects查找的实际实现是基于Knuth Vol. 3的算法D。如果你有这本书,它可能是值得一读的,此外,如果你真的非常感兴趣,你可能想看一下开发者对实际执行的dictobject的评论。它详细地描述了它是如何工作的。还有一个python的讲座,关于你可能感兴趣的字典的实现。它们会经过一个键的定义,在开始的几分钟里,哈希是什么。

#7


0  

According to the Python 2.7.2 documentation:

根据Python 2.7.2文档:

An object is hashable if it has a hash value which never changes during its lifetime (it needs a hash() method), and can be compared to other objects (it needs an eq() or cmp() method). Hashable objects which compare equal must have the same hash value.

如果对象的哈希值在其生命周期中从未改变(它需要一个hash()方法),并且可以与其他对象进行比较(它需要一个eq()或cmp()方法),那么这个对象就可以被使用。比较相等的可清洗对象必须具有相同的散列值。

Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

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

All of Python’s immutable built-in objects are hashable, while no mutable containers (such as lists or dictionaries) are. Objects which are instances of user-defined classes are hashable by default; they all compare unequal, and their hash value is their id().

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

A tuple is immutable in the sense that you cannot add, remove or replace its elements, but the elements themselves may be mutable. List's hash value depends on the hash values of its elements, and so it changes when you change the elements.

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

Using id's for list hashes would imply that all lists compare differently, which would be surprising and inconvenient.

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

#1


21  

There's a good article on the topic in the Python wiki: Why Lists Can't Be Dictionary Keys. As explained there:

在Python wiki中有一篇关于这个主题的好文章:为什么列表不能是字典密钥。作为解释:

What would go wrong if you tried to use lists as keys, with the hash as, say, their memory location?

如果您试图使用列表作为键,而使用散列,比如,它们的内存位置,那么会出现什么问题呢?

It can be done without really breaking any of the requirements, but it leads to unexpected behavior. Lists are generally treated as if their value was derived from their content's values, for instance when checking (in-)equality. Many would - understandably - expect that you can use any list [1, 2] to get the same key, where you'd have to keep around exactly the same list object. But lookup by value breaks as soon as a list used as key is modified, and for lookup by identity requires you to keep around exactly the same list - which isn't requires for any other common list operation (at least none I can think of).

它可以在不破坏任何需求的情况下完成,但它会导致意外的行为。列表通常被视为从其内容的值中派生出它们的值,例如在检查(in-)相等时。可以理解的是,许多人希望您可以使用任何列表[1,2]来获得相同的密钥,在那里您必须保留完全相同的列表对象。但是,当一个列表作为键被修改时,查找值就会中断,而为了查找,需要您保留完全相同的列表——这并不需要任何其他常见的列表操作(至少我能想到的)。

Other objects such as modules and object make a much bigger deal out of their object identity anyway (when was the last time you had two distinct module objects called sys?), and are compared by that anyway. Therefore, it's less surprising - or even expected - that they, when used as dict keys, compare by identity in that case as well.

其他的对象,比如模块和对象,无论如何都能从它们的对象标识中获得更大的好处(上次您有两个不同的模块对象,称为sys?),并将它们进行比较。因此,当被用作字典的关键字时,它们的身份也就不那么令人惊讶了,甚至是意料之中的。

#2


16  

Why can't I use a list as a dict key in python?

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

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

(for anybody who stumbles on this question looking for a way around it)

(对于任何在这个问题上有问题的人来说,寻找解决办法)

as explained by others here, indeed you cannot. You can however use its string representation instead if you really want to use your list.

正如这里的其他人所解释的那样,你确实不能。但是,如果你真的想使用你的列表,你可以使用它的字符串表示。

#3


9  

The issue is that tuples are immutable, and lists are not. Consider the following

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

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

What should d[li] return? Is it the same list? How about d[[1,2,3]]? It has the same values, but is a different list?

d(李)返回什么?是同一个列表吗?如何d[[1,2,3]]?它有相同的值,但是是不同的列表吗?

Ultimately, there is no satisfactory answer. For example, if the only key that works is the original key, then if you have no reference to that key, you can never again access the value. With every other allowed key, you can construct a key without a reference to the original.

最终,没有令人满意的答案。例如,如果唯一有效的键是原来的键,那么如果没有对该键的引用,就再也无法访问该值。使用所有其他允许的键,您可以构造一个关键字,而不需要引用原始。

If both of my suggestions work, then you have very different keys that return the same value, which is more than a little surprising. If only the original contents work, then your key will quickly go bad, since lists are made to be modified.

如果我的两个建议都有效,那么返回相同值的键就会非常不同,这就有点让人吃惊了。如果原来的内容是有效的,那么你的密钥就会很快变坏,因为列表是要修改的。

#4


7  

Here's an answer http://wiki.python.org/moin/DictionaryKeys

这里有一个回答http://wiki.python.org/moin/DictionaryKeys

What would go wrong if you tried to use lists as keys, with the hash as, say, their memory location?

如果您试图使用列表作为键,而使用散列,比如,它们的内存位置,那么会出现什么问题呢?

Looking up different lists with the same contents would produce different results, even though comparing lists with the same contents would indicate them as equivalent.

用相同的内容查找不同的列表会产生不同的结果,即使将列表与相同的内容进行比较也会表明它们是等价的。

What about Using a list literal in a dictionary lookup?

如何在字典查找中使用列表文字?

#5


2  

Your awnser can be found here:

你的awnser可以在这里找到:

Why Lists Can't Be Dictionary Keys

为什么列表不能是字典键?

Newcomers to Python often wonder why, while the language includes both a tuple and a list type, tuples are usable as a dictionary keys, while lists are not. This was a deliberate design decision, and can best be explained by first understanding how Python dictionaries work.

Python的新手常常想知道为什么,虽然语言既包括元组,也包括列表类型,元组可以用作字典键,而列表则不是。这是一个经过深思熟虑的设计决策,最好先理解Python字典是如何工作的。

Source & more info: http://wiki.python.org/moin/DictionaryKeys

来源&更多信息:http://wiki.python.org/moin/DictionaryKeys。

#6


0  

The simple answer to your question is that the class list does not implement the method hash which is required for any object which wishes to be used in as a key in a dictionary. However the reason why hash is not implemented the same way it is in say the tuple class (based on the content of the container) is because a list is mutable so editing the list would require the hash to be recalculated which may mean the list in now located in the wrong bucket within the underling hash table. Note that since you cannot modify a tuple (immutable) it doesn't run into this problem.

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

As a side note the actual implementation of the dictobjects lookup is based on Algorithm D from Knuth Vol. 3, Sec. 6.4. If you have that book available to you it might be a worthwhile read, in addition if your really really interested you may like to take a peek at the developer comments on the actual implementation of dictobject here. It goes into great detail as to exactly how it works. There is also a python lecture on the implementation of dictionaries which you may be interested in. They go through the definition of a key and what a hash is in the first few minutes.

另外,dictobjects查找的实际实现是基于Knuth Vol. 3的算法D。如果你有这本书,它可能是值得一读的,此外,如果你真的非常感兴趣,你可能想看一下开发者对实际执行的dictobject的评论。它详细地描述了它是如何工作的。还有一个python的讲座,关于你可能感兴趣的字典的实现。它们会经过一个键的定义,在开始的几分钟里,哈希是什么。

#7


0  

According to the Python 2.7.2 documentation:

根据Python 2.7.2文档:

An object is hashable if it has a hash value which never changes during its lifetime (it needs a hash() method), and can be compared to other objects (it needs an eq() or cmp() method). Hashable objects which compare equal must have the same hash value.

如果对象的哈希值在其生命周期中从未改变(它需要一个hash()方法),并且可以与其他对象进行比较(它需要一个eq()或cmp()方法),那么这个对象就可以被使用。比较相等的可清洗对象必须具有相同的散列值。

Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

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

All of Python’s immutable built-in objects are hashable, while no mutable containers (such as lists or dictionaries) are. Objects which are instances of user-defined classes are hashable by default; they all compare unequal, and their hash value is their id().

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

A tuple is immutable in the sense that you cannot add, remove or replace its elements, but the elements themselves may be mutable. List's hash value depends on the hash values of its elements, and so it changes when you change the elements.

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

Using id's for list hashes would imply that all lists compare differently, which would be surprising and inconvenient.

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