Множества

Тип set – это разновидность коллекций, которая поддерживает оператор проверки на вхождение in, функцию len() и относится к разряду итерируемых объектов. Кроме того, множества предоставляют метод set.isdisjoint() и поддерживают операторы сравнения и битовые операторы (которые в контексте множеств используются для получения объединения, пересечения и т. д.). В языке Python имеется два встроенных типа множеств: изменяемый тип set и неизменяемый frozenset. При переборе элементов множества элементы могут следовать в произвольном порядке.

В состав множеств могут включаться только хешируемые объекты. Хешируемые объекты – это объекты, имеющие специальный метод __hash__(), на протяжении всего жизненного цикла объекта всегда возвращающий одно и то же значение, которые могут участвовать в операциях сравнения на равенство посредством специального метода __eq__(). (Специальные методы – это методы, имена которых начинаются и оканчиваются двумя символами подчеркивания).

Все встроенные неизменяемые типы данных, такие как float, frozenset, int, str и tuple, являются хешируемыми объектами и могут добавляться во множества. Встроенные изменяемые типы данных, такие как dict, list и set, не являются хешируемыми объектами, так как значение хеша в каждом конкретном случае зависит от содержащихся в объекте элементов, поэтому они не могут добавляться в множества.

Множества могут сравниваться между собой с использованием стандартных операторов сравнения (<, <=, ==, !=, >=, >). Обратите внимание: операторы == и != имеют обычный смысл, и сравнение выполняется путем поэлементного сравнения (или рекурсивно при наличии таких вложенных элементов, как кортежи и фиксированные множества (frozenset)), но остальные операторы сравнения выполняют сравнение подмножеств и надмножеств, как вскоре будет показано.

Тип set

Тип set – это неупорядоченная коллекция из нуля или более ссылок на объекты, указывающих на хешируемые объекты. Множества относятся к категории изменяемых типов, поэтому легко можно добавлять и удалять их элементы, но, так как они являются неупорядоченными коллекциями, к ним не применимо понятие индекса и не применима операция извлечения среза. На рис. 3 иллюстрируется множество, созданное следующим фрагментом программного кода:

S = {7, "veil", 0, -29, ("x", 11), "sun", frozenset({8, 4, 7}), 913}


Рисунок 3: Множество – это неупорядоченная коллекция уникальных элементов

Тип данных set может вызываться как функция set() – без аргументов она возвращает пустое множество; с аргументом типа set возвращает поверхностную копию аргумента; в случае, если аргумент имеет другой тип, выполняется попытка преобразовать его в объект типа set. Эта функция принимает не более одного аргумента. Кроме того, непустые множества могут создаваться без использования функции set(), а пустые множества могут создаваться только с помощью функции set() – их нельзя создать с помощью пары пустых скобок. Множество, состоящее из одного или более элементов, может быть создано с помощью последовательности элементов, разделенных запятыми, заключенной в фигурные скобки. Другой способ создания множеств заключается в использовании генераторов множеств. Множества всегда содержат уникальные элементы – добавление повторяющихся элементов возможно, но не имеет смысла. Например, следующие три множества являются эквивалентными: set("apple"), set("aple") и {'e', 'p', 'a', 'l'}. Благодаря этой их особенности множества часто используются для устранения повторяющихся значений. Например, если предположить, что x – это список строк, то после выполнения инструкции x = list(set(x)) в списке останутся только уникальные строки, причем располагаться они могут в произвольном порядке.


Рисунок 4: Стандартные операторы множеств

Множества поддерживают встроенную функцию len() и быструю проверку на вхождение с помощью операторов in и not in. Они также предоставляют типичный набор операторов, как показано на рис. . Полный перечень методов и операторов, применимых к множествам, приводится в табл. collections:sets:tbl:1. Все методы семейства «update» (set.update(), set.intersection_update() и т. д.) могут принимать в качестве аргумента любые итерируемые объекты, но эквивалентные им комбинированные операторы присваивания (|=, &= и т. д.) требуют, чтобы оба операнда были множествами.

Таблица 2. Методы и операторы множеств

Синтаксис Описание
s.add(x) Добавляет элементы x во множество s, если они отсутствуют в s
s.clear() Удаляет все элементы из множества s
s.difference(t)или s-t Возвращает новое множество включающее элементы множества s, которые отсутствуют в множестве t
s.difference_update(t) или s-=t Удаляет из множества s все элементы, присутствующие в множестве t
s.discard(x) Удаляет элемент x из множества s, если он присутствует в множестве s
s.intersection(t) или s & t Возвращает новое множество, включающее элементы, присутствующие одновременно в множествах s и t
s.intersection_update(t) или s &= t Оставляет во множестве s пересечение множеств s и t
s.isdisjoint(t) Возвращает True, если множества s и t не имеют общих элементов
s.issubset(t) или s <= t Возвращает True, если множество s эквивалентно множеству t или является его подмножеством; чтобы проверить, является ли множество s только подмножеством множества t, следует использовать проверку s < t
s.issuperset(t) или s >= t Возвращает True, если множество s эквивалентно множеству t или является его надмножеством; чтобы проверить, является ли множество s только надмножеством множества t, следует использовать проверку s > t
s.pop() Возвращает и удаляет случайный элемент множества s или возбуждает исключение KeyError, если s – это пустое множество
s.remove(x) Удаляет элемент x из множества s или возбуждает исключение KeyError, если элемент x отсутствует в множестве s
s.symmetric_difference(t) или s ^ t Возвращает новое множество, включающее все элементы, присутствующие в множествах s и t, за исключением элементов, присутствующих в обоих множествах одновременно
s.symmetric_difference_update(t) или s ^= t Возвращает в множестве s результат строгой дизъюнкции множеств s и t
s.union(t) или s | t Возвращает новое множество, включающее все элементы множества s и все элементы множества t, отсутствующие в множестве s
s.update(t) или s |= t Добавляет во множество s все элементы множества t, отсутствующие в множестве s

Генераторы множеств

В дополнение к возможности создавать множества с помощью функции set() или литералов, существует возможность создавать множества с помощью генераторов множеств. Генератор множества – это выражение и цикл с необязательным условием, заключенные в фигурные скобки. Подобно генераторам списков, генераторы множеств поддерживают две формы записи:

{expression for item in iterable}
{expression for item in iterable if condition}

Мы могли бы использовать генераторы множеств для фильтрации нежелательных элементов (когда порядок следования элементов не имеет значения), как показано ниже:

html = {x for x in files if x.lower().endswith((".htm", ".html"))}

Если предположить, что files – это список имен файлов, то данный генератор множества создает множество html, в котором хранятся только имена файлов с расширениями .htm и .html, независимо от регистра символов.

Как и в случае с генераторами списков, в генераторах множеств используются итерируемые объеты, которые в свою очередь могут быть генераторами множеств (или генераторами любого другого типа), что позволяет создавать весьма замысловатые генераторы множеств.

Тип frozenset

Фиксированное множество (frozenset) – это множество, которое после создания невозможно изменить. Хотя при этом мы, конечно, можем повторно связать переменную, которая ссылалась на фиксированное множество, с чем-то другим. Фиксированные множества могут создаваться только в результате обращения к имени типа frozenset как к функции. При вызове frozenset() без аргументов возвращается пустое фиксированное множество; с аргументом типа frozenset возвращается поверхностная копия аргумента; если аргумент имеет другой тип, выполняется попытка преобразовать его в объект типа frozenset. Эта функция принимает не более одного аргумента.

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

Поскольку фиксированные множества относятся к категории неизменяемых объектов, они поддерживают только те методы и операторы, которые воспроизводят результат, не оказывая воздействия на фиксированное множество или на множества, к которым они применяются. В табл. collections:sets:tbl:1 перечислены все методы множеств из которых фиксированными множествами поддерживаются: frozenset.copy(), frozenset.difference() (-), frozenset.intersection() (&), frozenset.isdis-joint(), frozenset.issubset() (<= и < для выявления подмножеств), frozenset.issuperset() (>= и > для выявления надмножеств), frozenset.union() (|) и frozenset.symmetric_difference() (^).

Если двухместный оператор применяется ко множеству и фиксированному множеству, тип результата будет совпадать с типом операнда, стоящего слева от оператора. То есть если предположить, что f – это фиксированное множество, а s – это обычное множество, то выражение f & s вернет объект типа frozenset, а выражение s & f – объект типа set. В случае операторов == и != порядок операндов не имеет значения, и выражение f == s вернет True, только если оба множества содержат одни и те же элементы.

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