# Python 3 `Set`

> 原文： [https://javabeginnerstutorial.com/python-tutorial/python-3-set-2/](https://javabeginnerstutorial.com/python-tutorial/python-3-set-2/)

在上一篇文章中，我们讨论了 [Python 列表](https://javabeginnerstutorial.com/python-tutorial/python-list-2/)。但是 Python 3 `Set`是什么？ 集合是*唯一*项目的*无序*集合。

**无序**表示这种类型的集合不允许建立索引，并且您无法像列表或元组那样通过索引访问它们的元素。

**唯一**表示即使将同一元素多次放入集合中，每个元素在集合中也只有一次。

自然，您可以像使用列表或元组一样将字符串中的类型混合在一起。

## 创建 Python 集

有一些方法可以创建集合。 基本版本是列出花括号（`{}`）之间的所有元素。 但是，最常见的用法是当您要从列表中删除重复项时。 在这种情况下，您可以将列表转换为集合，然后再次返回列表。 这将从集合的中间用法中将重复项从列表中删除，您将再次拥有列表。 为此，使用`set`函数，该函数需要一个可迭代的参数。

```java
>>> A = {1,2,3,4,5}
>>> A
{1, 2, 3, 4, 5}
>>> B = set((1,2,3,4,5))
>>> B
{1, 2, 3, 4, 5}
>>> C = set([1,2,5,4,3,4,5])
>>> C
{1, 2, 3, 4, 5}
>>> D = set(1,2,3,4,5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: set expected at most 1 arguments, got 5
>>> D = set(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
```

如您所见，您不能将可变数量的参数作为参数或不可迭代的参数添加。

**但是！** 您可以传递字符串作为 set 函数的参数，因为（您可能还记得），字符串是 Python 中的字符列表。 在这种情况下，字符串将拆分为字符，并且每个字符在集合中仅存储一次。

```java
>>> D = set("Spam! Spam! Spam!")
>>> D
{'p', 'm', ' ', 'a', 'S', '!'}
```

而且因为我已经提到过，您可以使用集合来过滤列表的重复项，因此这里是示例：

```java
>>> l = [1,2,3,2,1,2,3,4,5,6,5,6,4,7,8,3,2,1,3,4,5,6]
>>> l
[1, 2, 3, 2, 1, 2, 3, 4, 5, 6, 5, 6, 4, 7, 8, 3, 2, 1, 3, 4, 5, 6]
>>> l = list(set(l))
>>> l
[1, 2, 3, 4, 5, 6, 7, 8]
```

此示例首先将`l`转换为一个集合，该集合将删除所有重复的元素，然后将集合折回为允许进行索引的列表。 我在进行网站抓取并亲自编写抓取逻辑时使用了这种类型的过滤。

## 更改 Python 集

集是可变的（不是一成不变的），因此您可以更改它们的元素。 更改意味着添加和删除元素。 由于集合不支持索引，因此无法像列表一样更改给定索引的元素。 试想一下，如果您可以更改一组中的一个元素，将会发生什么？ 必须每次在后台运行某种机制来过滤出可能的重复元素。 那将是无稽之谈，并且会使使用`set`非常缓慢。

这意味着我们仅需添加和删除元素。 与列表不同，您不能使用加法运算符（加号`+`）来扩展集合。 您必须使用`add()`或`update()`。 这两种方法的区别在于参数的数量和类型。

```java
>>> A = {1}
>>> A
{1}
>>> A.add(2)
>>> A
{1, 2}
>>> A.add({3})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> A.add((3))
>>> A
{1, 2, 3}
>>> A.add((3,4))
>>> A
{1, 2, 3, (3, 4)}
>>> A.add(5,6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add() takes exactly one argument (2 given)
>>> A.add([5,6],(7))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add() takes exactly one argument (2 given)
>>> A.update([5,6],(7))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>> A.update([5,6],(7,))
>>> A
{1, 2, 3, 5, 6, 7, (3, 4)}
>>> A.update([1,2,3,4])
>>> A
{1, 2, 3, 4, 5, 6, 7, (3, 4)}
```

如上例所示，您需要为`add`函数提供一个不可变的元素（就像创建集合时一样）。 更新功能采用多个参数，这些参数必须是集合。 这些集合是不可变的，也不必只是必须是集合。 在所有情况下，都避免重复。

## 移除元素

有时您需要根据各种条件删除元素。 在这种情况下，您有一些方法在每种情况下的行为都会略有不同。

```java
>>> A = {1, 2, 3, 4, 5, 6, 7, 8, 9, (3, 4)}
>>> A
{1, 2, 3, 4, 5, 6, 7, 8, 9, (3, 4)}
>>> A.remove((3,4))
>>> A
{1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> A.remove(3,4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: remove() takes exactly one argument (2 given)
>>> A.remove(5)
>>> A
{1, 2, 3, 4, 6, 7, 8, 9}
>>> A.remove(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 5
leanpub-start-insert
>>> A.discard(5)
leanpub-end-insert
>>> n = A.pop()
>>> n
1
>>> A
{2, 3, 4, 6, 7, 8, 9}
>>> A.clear()
>>> A
set()
>>> A.pop()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'pop from an empty set'
```

如您所见，`remove`函数仅使用一个参数，而不是更多。 即使使用`A.remove((3,4))`，我们也只提供一个元素—元组。 如果要添加多个元素，则会出现`TypeError`。 如果该键不存在于集合中，则在尝试使用`remove`摆脱键时会出现`KeyError`。 但是，如果给定密钥不在集合中，则丢弃不会产生任何噪音。 它默默地发出有关该应用的通知，该应用不知道集合的状态，因此不再打扰。

`pop`函数（就像我们已经知道的那样）采用集合中的一个元素，将其删除并返回。 如果集合为空，则将再次收到`KeyError`。 似乎在使用`pop`时总是返回第一个元素，但是您不知道集合中元素的顺序。 实现可能会改变它们存储元素的方式并记住：如果您自己运行应用，则不会看到集合中的元素。

## 冻结集

冻结集是一种特殊的集，它具有与普通集相同的属性，但是您不能更改其元素。 这意味着，一旦创建了冻结集，就必须遵守分配给它的值（自然地，重新分配变量始终是一种解决方案）。

我们来看一些例子。

```java
>>> A = frozenset([1,2,3,4,5])
>>> B = {2,4,6,8,10}
>>> A | B
frozenset({1, 2, 3, 4, 5, 6, 8, 10})
>>> A & B
frozenset({2, 4})
>>> A.add(6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'frozenset' object has no attribute 'add'
>>> A += {6}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +=: 'frozenset' and 'set'
>>> A += frozenset({6})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +=: 'frozenset' and 'frozenset'
```

如您在上面的示例中看到的那样，没有方法可以将新元素添加到冻结集中。 删除或更改元素也是如此。 好吧，`frozenset`被冻结了，仅供使用。

### 参考文献

*   [官方文档](https://docs.python.org/3/tutorial/datastructures.html)

