> **Источник:** https://python-all.ru/2.7/library/sets.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 8.7. [`sets`](https://python-all.ru/2.7/library/sets.html#module-sets) – Неупорядоченные коллекции уникальных элементов

Новое в версии 2.3.

Устарело с версии 2.6: Встроенные типы [`set`](https://python-all.ru/2.7/library/stdtypes.html#set)/[`frozenset`](https://python-all.ru/2.7/library/stdtypes.html#frozenset) заменяют этот модуль.

Модуль [`sets`](https://python-all.ru/2.7/library/sets.html#module-sets) предоставляет классы для создания и работы с неупорядоченными коллекциями уникальных элементов. Обычно используется для проверки принадлежности, удаления дубликатов из последовательности и выполнения стандартных математических операций над множествами, таких как пересечение, объединение, разность и симметрическая разность.

Как и другие коллекции, множества поддерживают `x in set`, `len(set)` и `for x in set`. Будучи неупорядоченной коллекцией, множество не запоминает положение элементов или порядок вставки. Поэтому множества не поддерживают индексацию, срезы и другое поведение, свойственное последовательностям.

Большинство приложений, работающих с множествами, используют класс [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set), который предоставляет все методы множества, кроме [`__hash__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__hash__). Для более сложных приложений, требующих хеш-функцию, класс [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet) добавляет метод [`__hash__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__hash__), но опускает методы, изменяющие содержимое множества. Оба класса [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set) и [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet) являются производными от `BaseSet`, абстрактного класса, полезного для определения, является ли объект множеством: `isinstance(obj, BaseSet)`.

Классы множеств реализованы с использованием словарей. Соответственно, требования к элементам множеств такие же, как к ключам словарей: а именно, элемент должен определять как [`__eq__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__eq__), так и [`__hash__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__hash__). В результате множества не могут содержать изменяемые элементы, такие как списки или словари. Однако они могут содержать неизменяемые коллекции, например кортежи или экземпляры [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet). Для удобства реализации множеств из множеств внутренние множества автоматически преобразуются в неизменяемую форму, например, `Set([Set(['dog'])])` преобразуется в `Set([ImmutableSet(['dog'])])`.

#### `class sets.Set([iterable])`

Создаёт новый пустой объект [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set). Если указан необязательный параметр *iterable*, обновляет множество элементами, полученными при итерации. Все элементы в *iterable* должны быть неизменяемыми или преобразуемыми в неизменяемые с помощью протокола, описанного в разделе [Протокол автоматического преобразования в неизменяемые](https://python-all.ru/2.7/library/sets.html#immutable-transforms).

#### `class sets.ImmutableSet([iterable])`

Создаёт новый пустой объект [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet). Если указан необязательный параметр *iterable*, обновляет множество элементами, полученными при итерации. Все элементы в *iterable* должны быть неизменяемыми или преобразуемыми в неизменяемые с помощью протокола, описанного в разделе [Протокол автоматического преобразования в неизменяемые](https://python-all.ru/2.7/library/sets.html#immutable-transforms).

Поскольку объекты [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet) предоставляют метод [`__hash__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__hash__), они могут использоваться как элементы множества или как ключи словаря. Объекты [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet) не имеют методов для добавления или удаления элементов, поэтому все элементы должны быть известны на момент вызова конструктора.

## 8.7.1. Объекты множеств

Экземпляры [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set) и [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet) предоставляют следующие операции:

| Операция | Эквивалентно | Результат |
| --- | --- | --- |
| `len(s)` |  | количество элементов в множестве *s* (мощность) |
| `x in s` |  | проверить принадлежность *x* множеству *s* |
| `x not in s` |  | проверить, что *x* не принадлежит множеству *s* |
| `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()` принимают любой итерируемый объект в качестве аргумента. В отличие от них, операторные аналоги требуют, чтобы их аргументы были множествами. Это исключает подверженные ошибкам конструкции вроде `Set('abc') & 'cbs'` в пользу более читаемых `Set('abc').intersection('cbs')`.

Изменено в версии 2.3.1: Ранее все аргументы должны были быть множествами.

Кроме того, оба типа [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set) и [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet) поддерживают сравнение множеств. Два множества равны тогда и только тогда, когда каждый элемент одного множества содержится в другом (каждое является подмножеством другого). Множество меньше другого множества тогда и только тогда, когда первое множество является строгим подмножеством второго (является подмножеством, но не равным). Множество больше другого множества тогда и только тогда, когда первое множество является строгим надмножеством второго (является надмножеством, но не равным).

Сравнения на подмножество и равенство не обобщаются до функции полного упорядочения. Например, любые два непересекающихся множества не равны и не являются подмножествами друг друга, поэтому *все* следующие выражения возвращают `False`: `a<b`, `a==b`, или `a>b`. Соответственно, множества не реализуют метод [`__cmp__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__cmp__).

Поскольку множества определяют лишь частичное упорядочение (отношения подмножеств), результат метода `list.sort()` для списков множеств не определён.

В следующей таблице перечислены операции, доступные в [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet), но отсутствующие в [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set):

| Операция | Результат |
| --- | --- |
| `hash(s)` | возвращает хеш-значение для *s* |

В следующей таблице перечислены операции, доступные в [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set), но отсутствующие в [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet):

| Операция | Эквивалентно | Результат |
| --- | --- | --- |
| `s.update(t)` | *s* \|= *t* | возвращает множество *s* с элементами, добавленными из *t* |
| `s.intersection_update(t)` | *s* &= *t* | возвращает множество *s*, сохраняя только eлементы, также найденные в *t* |
| `s.difference_update(t)` | *s* -= *t* | возвращает множество *s* после удаления eлементов, найденных в *t* |
| `s.symmetric_difference_update(t)` | *s* ^= *t* | возвращает множество *s* с элементами из *s* или *t*, но не из обоих |
| `s.add(x)` |  | добавляет элемент *x* в множество *s* |
| `s.remove(x)` |  | удаляет *x* из множества *s*; вызывает [`KeyError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.KeyError), если отсутствует |
| `s.discard(x)` |  | удаляет *x* из множества *s*, если присутствует |
| `s.pop()` |  | удаляет и возвращает произвольный element из *s*; вызывает [`KeyError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.KeyError), если пусто |
| `s.clear()` |  | удаляет все элементы из множества *s* |

Примечание: неоператорные версии `update()`, `intersection_update()`, `difference_update()` и `symmetric_difference_update()` принимают любой итерируемый объект в качестве аргумента.

Изменено в версии 2.3.1: Ранее все аргументы должны были быть множествами.

Также обратите внимание: модуль также включает метод `union_update()`, который является псевдонимом для `update()`. Этот метод включён для обратной совместимости. Программистам следует предпочитать метод `update()`, поскольку он поддерживается встроенными типами [`set()`](https://python-all.ru/2.7/library/stdtypes.html#set) и [`frozenset()`](https://python-all.ru/2.7/library/stdtypes.html#frozenset).

## 8.7.2. Пример

```python
>>> 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           # объединение
>>> engineering_management = engineers & managers            # пересечение
>>> fulltime_management = managers - engineers - programmers # разность
>>> engineers.add('Marvin')                                  # добавляет элемент
>>> print engineers 
Set(['Jane', 'Marvin', 'Janice', 'John', 'Jack'])
>>> employees.issuperset(engineers)     # проверка надмножества
False
>>> employees.update(engineers)         # обновление из другого множества
>>> employees.issuperset(engineers)
True
>>> for group in [engineers, programmers, managers, employees]: 
...     group.discard('Susan')          # безусловное удаление элемента
...     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`](https://python-all.ru/2.7/library/sets.html#sets.Set) автоматически копируются в [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet) перед добавлением в качестве элемента множества.

Механизм заключается в том, чтобы всегда добавлять [хэшируемый](https://python-all.ru/2.7/glossary.html#term-hashable) элемент, или, если он не хэшируемый, элемент проверяется на наличие метода `__as_immutable__()`, который возвращает неизменяемый эквивалент.

Поскольку объекты [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set) имеют метод `__as_immutable__()`, возвращающий экземпляр [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet), можно создавать множества множеств.

Похожий механизм нужен методам [`__contains__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__contains__) и `remove()`, которым требуется хэшировать элемент для проверки членства в множестве. Эти методы проверяют элемент на хэшируемость и, если она отсутствует, ищут метод `__as_temporarily_immutable__()`, который возвращает элемент, обёрнутый классом, предоставляющим временные методы для [`__hash__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__hash__), [`__eq__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__eq__), и [`__ne__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__ne__).

Альтернативный механизм избавляет от необходимости создавать отдельную копию исходного изменяемого объекта.

Объекты [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set) реализуют метод `__as_temporarily_immutable__()`, который возвращает объект [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set), обёрнутый новым классом `_TemporarilyImmutableSet`.

Два механизма добавления хэшируемости обычно невидимы для пользователя; однако может возникнуть конфликт в многопоточной среде, где один поток обновляет множество, а другой временно обернул его в `_TemporarilyImmutableSet`. Другими словами, множества изменяемых множеств не являются потокобезопасными.

## 8.7.4. Сравнение со встроенными типами [`set`](https://python-all.ru/2.7/library/stdtypes.html#set)

Встроенные типы [`set`](https://python-all.ru/2.7/library/stdtypes.html#set) и [`frozenset`](https://python-all.ru/2.7/library/stdtypes.html#frozenset) были разработаны на основе уроков, извлечённых из модуля [`sets`](https://python-all.ru/2.7/library/sets.html#module-sets). Ключевые отличия:

- [`Set`](https://python-all.ru/2.7/library/sets.html#sets.Set) и [`ImmutableSet`](https://python-all.ru/2.7/library/sets.html#sets.ImmutableSet) были переименованы в [`set`](https://python-all.ru/2.7/library/stdtypes.html#set) и [`frozenset`](https://python-all.ru/2.7/library/stdtypes.html#frozenset).
- Нет эквивалента для `BaseSet`. Вместо этого используйте `isinstance(x, (set, frozenset))`.
- Алгоритм хэширования для встроенных типов работает значительно лучше (меньше коллизий) для большинства наборов данных.
- Встроенные версии создают более компактные pickle-объекты.
- Встроенные версии не имеют метода `union_update()`. Вместо этого используйте метод `update()`, который является эквивалентным.
- Встроенные версии не имеют метода `_repr(sorted=True)`. Вместо этого используйте встроенные функции [`repr()`](https://python-all.ru/2.7/library/functions.html#repr) и [`sorted()`](https://python-all.ru/2.7/library/functions.html#sorted): `repr(sorted(s))`.
- Встроенная версия не имеет протокола автоматического преобразования в неизменяемый тип. Многие находили эту функцию сбивающей с толку, и никто в сообществе не сообщал о её реальном применении.
