5. Python数据类型
5.10 冻结集合类型

基本概念

在上节中,我们讲解了 Python 中的集合类型,提到集合类型是可变的,也就是说,我们可以在创建一个集合对象后,对它进行修改。但是,很多时候,我们也需要一个不可变的集合对象;类似于元组和列表的关系,Python 也为我们提供了一个不可变的集合类型,叫做:冻结集合类型。

在 Python 中,冻结集合(Frozenset)是一种不可变的、无序的数据集合。冻结集合的内容和长度在创建之后都不能改变。

冻结集合的用法与普通集合非常相似,但是我们不能在创建后,再对冻结集合进行修改操作,例如添加、删除和修改元素;因此,我们可以把冻结集合类型看作是集合类型的不可变版本。

为什么我们需要一个不可变的集合呢?因为这样可以防止程序意外地修改数据。

下面列出了一些冻结集合类型与普通集合类型的主要区别:

  • 用途:当我们需要存储一组唯一的可变元素时,使用集合;而当我们需要存储一组唯一的不可变元素时,使用冻结集合。
  • 可哈希性:冻结集合类型是可哈希的,这意味着它可以用作字典中的键或其他集合中的元素;而普通集合则不可哈希。
  • 性能:在某些操作中,普通集合比冻结集合的性能更好,因为它可以在原地修改,而冻结集合在进行任何修改时都需要创建一个新对象。
  • 内存:在某些用例中,冻结集合比普通集合更节省内存,尤其是当我们需要存储许多具有相同元素的不可变集合时。由于冻结集合类型是不可变的,具有相同元素的多个冻结集合对象可以共享相同的内存。

下面,让我们来看一下冻结集合类型在 Python 中的基本操作。

基本操作

在 Python 中,如果要创建一个冻结集合类型对象,我们可以使用 frozenset() 函数。该函数接受一个可迭代对象(例如列表或集合)作为参数,并返回一个新的 frozenset 对象。以下是一个示例:

my_frozenset = frozenset([1, 2, 3])

在上面的示例中,我们创建一个名为 my_frozenset 的冻结集合类型对象,其中包含元素 123

如前所述,冻结集合的用法与普通集合非常类似,我们只是不能再对冻结集合进行修改操作,因此,我们基本可以沿用集合类型的方法来处理冻结集合类型,例如:

# 创建一个空冻结集合
fs1 = frozenset()
 
# 创建一个包含数字的冻结集合
fs2 = frozenset({1, 2, 3, 4, 5})
 
# 创建一个包含字符串的冻结集合
fs3 = frozenset({'apple', 'banana', 'cherry'})
 
# 创建一个包含混合类型的冻结集合
fs4 = frozenset({1, 'apple', True, 3.14})
 
# 将列表转换为冻结集合
fs5 = frozenset([1, 2, 3, 4, 5])
 
# 将元组转换为冻结集合
fs6 = frozenset((1, 2, 3, 4, 5))
 
# 计算冻结集合的长度
len(fs1)
 
# 判断元素是否在冻结集合中
1 in fs1
 
# 计算并集
fs1 | fs2
 
# 计算交集
fs1 & fs2
 
# 计算差集
fs1 - fs2

第 5.12 节中介绍的处理集合类型的 Python 内置方法,基本上也适合冻结集合类型,例如:

  • len():计算冻结集合的长度,即冻结集合中元素的数量。
  • in:判断指定的元素是否在冻结集合中。
  • union():计算两个冻结集合的并集。
  • intersection():计算两个冻结集合的交集。
  • difference():计算两个冻结集合的差集。
  • symmetric_difference():计算两个冻结集合的对称差集。
  • issubset():判断一个冻结集合是否是另一个冻结集合的子集。
  • issuperset():判断一个冻结集合是否是另一个冻结集合的超集。

同样,我们也可以使用 |&- 运算符来计算冻结集合的并集、交集和差集。

具体的使用方法,大家可以参考上一节对各个方法的介绍,我们就不在此赘述了。下面是一些简单的示例参考。

fs1 = frozenset({1, 2, 3, 4, 5})
fs2 = frozenset({4, 5, 6, 7, 8})
 
# 计算并集
fs1.union(fs2)
 
# 计算交集
fs1.intersection(fs2)
 
# 计算差集
fs1.difference(fs2)
 
# 计算对称差集
fs1.symmetric_difference(fs2)
 
# 判断 fs1 是否是 fs2 的子集
fs1.issubset(fs2)
 
# 判断 fs1 是否是 fs2 的超集
fs1.issuperset(fs2)

总结

综上所述,在 Python 中,冻结集合(Frozenset)类型是一个不可变的(不可更改)集合。就像普通集合一样,它是一组唯一元素的无序集合,但一旦创建,就无法修改。这意味着我们无法向冻结集合对象中添加或删除元素,也无法修改已经存在的元素;但是,我们依然可以在冻结集合对象上执行不需要修改的操作,例如并集、交集和差集。

在实际的 Python 开发中,冻结集合类型主要用于以下场景:

  • 用作字典中的键:由于冻结集合类型是不可变的,因此可以将其用作字典中的键。这在我们想要将值与元素集相关联,并且希望能够基于相同的元素集稍后查找值时很有用。
  • 用作其他集合中的元素:由于冻结集合类型是不可变的,因此也可以将其用作其他集合中的元素。这在我们想要创建一组集合时很有用,其中每个集合表示唯一的元素集。
  • 缓存函数的结果:如果我们有一个函数,它以元素集作为输入,并基于这些元素返回结果,则可以使用具有冻结集合对象的键的字典来缓存结果。这可以通过避免在相同的元素集上调用时进行冗余计算来帮助加快函数速度。
  • 存储唯一的元素集:如果我们有一组集合,并且想要删除重复项,则可以创建一个冻结集合对象的集合。由于每个冻结集合对象表示唯一的元素集,因此可以使用此集合有效地删除重复项。
  • 处理并发访问:如果我们正在处理多个线程或进程访问共享元素集的情况,则使用冻结集合类型可以帮助避免出现竞态条件和其他问题,这些问题可能会在处理可变数据结构时出现。

总之,在 Python 中,冻结集合类型可以帮助我们实现数据的不可变性,防止程序意外地修改数据,因此,在不少场景中,冻结集合类型都非常有用。