8.7. 套-独特元素的无序集合

2.3 版的新Function。

从 2.6 版开始不推荐使用:内置的set/frozenset类型替换此模块。

sets模块提供了一些类,用于构造和处理无序的唯一元素集合。常见用途包括成员资格测试,从序列中删除重复项,以及在诸如交集,并集,差和对称差之类的集合上计算标准 math 运算。

与其他集合一样,集合支持x in setlen(set)for x in set。集是无序集合,不记录元素位置或插入 Sequences。因此,集合不支持索引,切片或其他类似序列的行为。

大多数 set 应用程序使用Set类,该类提供hash()之外的所有 set 方法。对于需要哈希方法的高级应用程序,ImmutableSet类添加了hash()方法,但Ellipsis了会更改集合内容的方法。 SetImmutableSet都从BaseSet派生而来,BaseSet是用于确定某物是否为集合的抽象类:isinstance(obj, BaseSet)

集合类使用字典来实现。因此,对设置元素的要求与对字典键的要求相同。也就是说,该元素同时定义了eq()hash()。结果,集合不能包含可变元素,例如列表或字典。但是,它们可以包含不可变的集合,例如 Tuples 或ImmutableSet的实例。为了方便实现集合集,内部集合会自动转换为不可变形式,例如Set([Set(['dog'])])转换为Set([ImmutableSet(['dog'])])

  • 类别 sets. Set([可迭代])

    • 构造一个新的空Set对象。如果提供了可选的* iterable *参数,则使用从迭代获得的元素更新集合。 * iterable *中的所有元素都应该是不可变的,或者可以使用自动转换为不可变的协议部分中描述的协议将其转换为不可变的。
  • 类别 sets. ImmutableSet([可迭代])

    • 构造一个新的空ImmutableSet对象。如果提供了可选的* iterable *参数,则使用从迭代获得的元素更新集合。 * iterable *中的所有元素都应该是不可变的,或者可以使用自动转换为不可变的协议部分中描述的协议将其转换为不可变的。

由于ImmutableSet对象提供hash()方法,因此它们可用作设置元素或字典键。 ImmutableSet对象没有添加或删除元素的方法,因此在调用构造函数时必须知道所有元素。

8.7.1. 设置对象

SetImmutableSet的实例均提供以下操作:

OperationEquivalentResult
len(s)集合* s *中的元素数(基数)
x in s测试* x 是否属于 s *
x not in s在* s 中测试 x *是否为非会员
s.issubset(t)s <= t测试* s 中的每个元素是否在 t *中
s.issuperset(t)s >= t测试* t 中的每个元素是否在 s *中
s.union(t)s | t包含* s t *元素的新集合
s.intersection(t)s & t新集合,具有* s t *共有的元素
s.difference(t)s - t元素在* s 中但不在 t *中的新集合
s.symmetric_difference(t)s ^ t* s t *中包含元素但不同时包含两者的新集合
s.copy()带有* s *浅表副本的新集

请注意,union()intersection()difference()symmetric_difference()的非运算符版本将接受任何 iterable 作为参数。相反,其基于运算符的对应项要求将其参数设置为。这就避免了像Set('abc') & 'cbs'这样的易于出错的结构,而采用了更具可读性的Set('abc').intersection('cbs')

在 2.3.1 版中进行了更改:以前,所有参数都必须设置。

此外,SetImmutableSet支持均设置为设置比较。当且仅当每个集合的每个元素都包含在另一个集合中(每个元素是另一个子集)时,两个集合才相等。当且仅当第一集合是第二集合的适当子集(是子集,但不相等)时,一个集合小于另一个集合。当且仅当第一个集合是第二个集合的适当超集(是一个超集,但不相等)时,一个集合才大于另一个集合。

子集和相等性比较不能推广到完整的排序Function。例如,任何两个不相交的集合都不相等,也不是彼此的子集,因此以下所有*都返回Falsea<ba==ba>b。因此,集合不实现cmp()方法。

由于集合仅定义部分排序(子集关系),因此对于集合列表未定义list.sort()方法的输出。

下表列出了ImmutableSet中可用但在Set中找不到的操作:

OperationResult
hash(s)返回* s *的哈希值

下表列出了Set中可用但在ImmutableSet中找不到的操作:

OperationEquivalentResult
s.update(t)* s *= * t *返回从* t 添加元素的集合 s *
s.intersection_update(t)* s *&= * t *返回集* s 仅保留 t *中也存在的元素
s.difference_update(t)* s *-= * t *删除* t *中的元素后,返回 set * s *
s.symmetric_difference_update(t)* s * ^ = * t *返回带有* s t 中的元素的集合 s *,但不能同时包含两者
s.add(x)添加元素* x 以设置 s *
s.remove(x)从集合* s 中删除 x *;如果不存在则加注KeyError
s.discard(x)如果存在,则从集合* s 中删除 x *
s.pop()从* s *移除并返回任意元素;如果为空,则引发KeyError
s.clear()从集合* s *中删除所有元素

请注意,update()intersection_update()difference_update()symmetric_difference_update()的非运算符版本将接受任何 iterable 作为参数。

在 2.3.1 版中进行了更改:以前,所有参数都必须设置。

还要注意,该模块还包含union_update()方法,该方法是update()的别名。包含该方法是为了向后兼容。程序员应首选update()方法,因为内置的set()frozenset()类型支持该方法。

8.7.2. Example

>>> from sets import Set
>>> engineers = Set(['John', 'Jane', 'Jack', 'Janice'])
>>> programmers = Set(['Jack', 'Sam', 'Susan', 'Janice'])
>>> managers = Set(['Jane', 'Jack', 'Susan', 'Zack'])
>>> employees = engineers | programmers | managers           # union
>>> engineering_management = engineers & managers            # intersection
>>> fulltime_management = managers - engineers - programmers # difference
>>> engineers.add('Marvin')                                  # add element
>>> print engineers 
Set(['Jane', 'Marvin', 'Janice', 'John', 'Jack'])
>>> employees.issuperset(engineers)     # superset test
False
>>> employees.update(engineers)         # update from another set
>>> employees.issuperset(engineers)
True
>>> for group in [engineers, programmers, managers, employees]: 
...     group.discard('Susan')          # unconditionally remove element
...     print group
...
Set(['Jane', 'Marvin', 'Janice', 'John', 'Jack'])
Set(['Janice', 'Jack', 'Sam'])
Set(['Jane', 'Zack', 'Jack'])
Set(['Jack', 'Sam', 'Jane', 'Marvin', 'Janice', 'John', 'Zack'])

8.7.3. 自动转换为不可变的协议

集只能包含不可变元素。为方便起见,可变的Set对象在添加为集合元素之前会自动复制到ImmutableSet

该机制是始终添加hashable元素,或者如果该元素不可哈希,则检查该元素以查看其是否具有返回不可变等效项的__as_immutable__()方法。

由于Set个对象使用__as_immutable__()方法返回ImmutableSet的实例,因此可以构造集合集。

contains()remove()方法需要类似的机制,这些方法需要对元素进行哈希处理以检查集合中的成员资格。这些方法检查元素的可哈希性,如果不是,则检查__as_temporarily_immutable__()方法,该方法返回由为hash()eq()ne()提供临时方法的类包装的元素。

备用机制无需构建原始可变对象的单独副本。

Set对象实现__as_temporarily_immutable__()方法,该方法返回由新类_TemporarilyImmutableSet包装的Set对象。

用户通常看不到两种增加哈希值的机制;但是,在多线程环境中可能会发生冲突,其中一个线程正在更新集合,而另一个线程将其暂时包装在_TemporarilyImmutableSet中。换句话说,可变集的集合不是线程安全的。

8.7.4. 与内置集合类型的比较

内置的setfrozenset类型是根据从sets模块中学到的经验设计的。关键区别在于:

  • SetImmutableSet重命名为setfrozenset

  • 没有等效于BaseSet。而是使用isinstance(x, (set, frozenset))

  • 对于大多数数据集,内置的哈希算法的性能要好得多(冲突更少)。

  • 内置版本具有更节省空间的 pickle。

  • 内置版本没有union_update()方法。而是使用等效的update()方法。

  • 内置版本没有_repr(sorted=True)方法。而是使用内置的repr()sorted()函数:repr(sorted(s))

  • 内置版本没有用于自动转换为不可变的协议。许多人发现此Function令人困惑,社区中没有人报告已找到该Function的 true 用途。