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

2022-01-19 00:00:00 python list dictionary tuples hashable

问题描述

我对什么可以/不能用作 python dict 的键有点困惑.

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

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?


解决方案

在 Python wiki 中有一篇关于该主题的好文章:Why列表不能是字典键.如那里所述:

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

如果您尝试使用列表作为键,而将哈希作为它们的内存位置,会出现什么问题?

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

它可以在没有真正破坏任何要求的情况下完成,但它会导致意外行为.列表通常被视为其值源自其内容的值,例如在检查(不)相等性时.许多人会 - 可以理解 - 期望您可以使用任何列表 [1, 2] 来获得相同的密钥,而您必须保持完全相同的列表对象.但是,一旦用作键的列表被修改,按值查找就会中断,并且对于按标识查找要求您保持完全相同的列表 - 这对于任何其他常见的列表操作都不是必需的(至少我没有想到).

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).

其他对象,如模块和 object 无论如何都会从它们的对象标识中获得更大的收益(您上一次拥有两个名为 sys 的不同模块对象是什么时候?),并且无论如何都要进行比较.因此,当它们用作 dict 键时,在这种情况下也会按身份进行比较,这并不令人惊讶 - 甚至是预期的.

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.

相关文章