为什么Python不支持集合嵌套?
>>> li = [2, [3, 4]]
>>> 3 in li
False
>>> {2, {3, 4}}
TypeError: unhashable type: 'set'
为什么在Python(2.x和3.x)中没有实现集合嵌套(这是数学中使用的一种概念)?
2 个回答
正如@Martin Pieters提到的,如果你使用frozenset对象而不是普通的集合,那是可以的,因为frozenset对象是可以被哈希的。
原因在于,Python中的普通容器(比如列表、字典、集合等)都是可变的,这意味着它们在使用过程中可以改变(比如可以往集合里添加元素)。可变的数据类型不能被哈希(因为哈希的意思就是用一个独特的数字来标识一个不可变的对象)。
frozenset对象是可以被哈希的,这意味着它们可以用在集合中,但这也意味着一旦创建了frozenset,就不能再对它进行修改(frozenset没有update()这个方法)。所以如果你想要改变一个嵌套在集合里的frozenset,你需要从这个frozenset创建一个新的集合,对这个新集合进行修改,然后把旧的frozenset移除,再把新的集合转换成frozenset并添加进去(这听起来有点复杂,如果你觉得难理解可以告诉我)。
集合只能包含可哈希对象的原因是,每个集合中的对象必须是唯一的,Python通过使用对象的哈希值来检查这一点,因为这样做既高效又安全。
这个功能已经实现了,但你需要使用一种叫做可哈希类型的东西。frozenset()
就是这种类型。文档里也提到过这一点:
要表示集合中的集合,里面的集合必须是
frozenset
对象。
示例:
>>> {2, frozenset([3, 4])}
set([frozenset([3, 4]), 2])
这是因为普通的set()
是可变的,这和用来存储集合(和字典)的数据结构的要求不符;这些数据结构需要稳定的对象,这样在根据它们的哈希值作为表中的键时才能重新定位。
文档再次说明:
set
类型是可变的——内容可以通过add()
和remove()
等方法进行更改。由于它是可变的,所以没有哈希值,不能用作字典的键或另一个集合的元素。而frozenset
类型是不可变的,并且是可哈希的——它的内容在创建后不能被更改;因此可以用作字典的键或另一个集合的元素。