问题描述
我在一本书中读到,由于“算法基础”,只能将不可变类型的实例添加到 Python set
,但它没有解释什么是“算法基础”。
在尝试实际添加要设置的列表(可变数据类型)后,我收到一条错误消息,提示 TypeError: unhashable type: list
,但为什么要添加的项目必须是可散列的?
>>> my_set = set()
>>> my_set.add('a')
>>> my_set.add(1)
>>> my_set.add((1,2,3))
>>> my_set.add([1,3])
Traceback (most recent call last):
File "<stdin>",line 1,in <module>
TypeError: unhashable type: 'list'
解决方法
集合对象是不同的可散列对象的无序集合
和
如果一个对象的哈希值在其生命周期内永远不会改变(它需要一个 __hash__()
方法),并且可以与其他对象进行比较(它需要一个 __eq__()
方法),那么它就是可散列的。比较相等的可散列对象必须具有相同的散列值。
为了解释这意味着什么,集合/字典基于哈希表的概念,其中所有的键不是用它们的实际值存储,而是用它们的哈希存储。散列是从键值计算出来的整数。
例如,如果我想将键 k="Hello"
插入具有散列函数 f(k) = sum of all ASCII values
的集合中,那么您将获得 Hash of k = f(k) = 72+101+108+108+111 = 500
,并且您将存储 k
在位置 500
(当然比这个复杂很多,只是个蠢例子)。
这样当你想检查 k
是否在集合中时,你不必做线性搜索,但你可以计算它的散列并在索引 500 处检查是否有东西,所以它是快多了。 (这就是为什么当集合有很多元素时,集合比列表快得多)。
小问题:如果你的键是一个列表,你可以修改它,这会改变它的散列,所以每次修改列表时,你需要编辑包含它的所有集合/字典,它会是一团糟,所以最好避免可变类型,这就是列表不可散列的原因。