我发现以下内容都是有效的:
>>> d = {}
>>> d[None] = 'foo'
>>> d[(1, 3)] = 'baz'
甚至模块也可以用作字典键:
>>> import sys
>>> d[sys] = 'bar'
但是,列表不能,包含列表的元组也不能:
>>> d[[2]] = 'spam'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> d[(1, [3])] = 'qux'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
为什么在元组中存储列表意味着它不能再是字典键?毕竟,我可以轻松地“隐藏”模块内的列表(实际上,例如sys.path
已经是一个列表)。
我有一些模糊的想法,即密钥必须是“可散列的”,但我没有详细理解这意味着什么,或者为什么会有这样的限制。如果 Python 允许使用列表作为键,例如使用它们的内存位置作为散列,会出现什么问题?
Python wiki 中有一篇关于该主题的好文章:为什么列表不能作为字典键。正如那里所解释的:
如果 Python 允许使用列表作为键,例如使用它们的内存位置作为散列,会出现什么问题?
这会导致一些意想不到的行为。列表通常被视为它们的值源自其内容的值,例如在检查(不)相等时。许多人会 - 可以理解 - 期望你可以使用任何列表[1, 2]
要获得相同的密钥,您必须保留完全相同的列表对象。但是,一旦用作键的列表被修改,按值查找就会中断,并且按身份查找需要跟踪该确切的列表对象 - 这不是使用列表的一般要求。
其他对象,例如模块和object
,无论如何,都要从它们的对象标识中进行更大的处理(最后一次你有两个不同的模块对象被称为sys
?),并以此进行比较。因此,当它们用作字典键时,在这种情况下也会按身份进行比较,这并不令人惊讶 - 甚至是预期的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)