Множества и словари в Python
Множество ( set ) — встроенная структура данных языка Python, имеющая следующие свойства:
- множество — это коллекция Множество содержит элементы
- множество неупорядоченно Множество не записывает (не хранит) позиции или порядок добавления его элементов. Таким образом, множество не имеет свойств последовательности (например, массива): у элементов множества нет индексов, невозможно взять срез множества.
- элементы множества уникальны Множество не может содержать два одинаковых элемента.
- элементы множества — хешируемые объекты (hashable objects) В Python множество set реализовано с использованием хеш-таблицы. Это приводит к тому, что элементы множества должны быть неизменяемыми объектами. Например, элементом множества может быть строка, число, кортеж tuple , но не может быть список list , другое множество set .
Эти свойства множеств часто используются, чтобы проверять вхождение элементов, удаление дубликатов из последовательностей, а также для математических операций пересечения, объединения, разности.
Создание и изменение множества
Запустите в терминале Python в интерпретируемом режиме и проработайте примеры ниже.
Пустое множество создаётся с помощью функции set
>>> A = set() >>> type(A) >>> len(A) 0 >>> A set()
Обратите внимание, что размер множества множества можно получить с помощью функции len .
Добавим несколько элементов
>>> A.add(1) >>> A >>> A.add(2) >>> A >>> A.add(2) >>> A
Заметьте, что повторное добавление не имеет никакого эффекта на множество.
Также, из вывода видно, что литералом множества являются фигурные скобки <>, в которых через запятую указаны элементы. Так, ещё один способ создать непустое множество — воспользоваться литералом
>>> B = 1, 2> >>> B
При попытке добавления изменяемого объекта возникнет ошибка
>>> B.add([3,4,5]) Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: 'list'
Здесь произошла попытка добавить массив в множество B.
У операции добавления set.add существует обратная — операция удаления set.remove
>>> B >>> B.remove(1) >>> B >>> B.remove(3) Traceback (most recent call last): File "", line 1, in KeyError: 3
При попытке удаления элемента, не входящего в множество, возникает ошибка KeyError .
Однако, существует метод set.discard , который удаляет элемент из множества, только в том случае, если этот элемент присутствовал в нём.
Математические операции
Множества Python поддерживают привычные математические операции
Проверки
Чтобы проверить вхождение элемента в множество используйте логический оператор in
>>> B = 1, 2> >>> B >>> 3 in B False
Асимптотика x in set — O(1).
Стоит отметить, что оператор in работает и с другими коллекциями. Например, можно проверять вхождение подстроки в строку ‘AA’ in ‘bbAAcc’ или вхождение элемента в массив 5 in [1, 2, 5, 6] . Асимптотики в данном случае нужно уточнять в документации.
>>> A = 1, 2, 3> >>> B = 1, 2, 3> >>> A == B True >>> B.add(4) >>> A >>> B >>> A == B False
Проверка на нестрогое подмножество set.issubset
>>> A >>> B >>> A.issubset(B) True >>> B.issubset(A) False >>> A.issubset(A) True
Проверка на нестрогое надмножество set.issuperset
>>> A >>> B >>> A.issuperset(B) False >>> B.issuperset(A) True >>> B.issuperset(B) True
Операции получения новых множеств
>>> A = 1, 2, 4> >>> B = 1, 2, 3> >>> A.union(B) # union — объединение множеств >>> A.intersection(B) # intersection — пересечение >>> A.difference(B) # difference — разность множеств >>> B.difference(A) >>> A.symmetric_difference(B) # symmetric_difference — симметрическая разность >>> B.symmetric_difference(A)
Сводная таблица по множествам (cheatsheet)
Кроме того, у операций, порождающих новые множества, существует inplace варианты. Для методов это те же названия, только с префиксом _update, а для соответствующих операторов добавляется знак равенства =. Ниже показан вариант для операции разности множеств
>>> A = 1, 2, 3, 4> >>> B = 2, 4> >>> A.difference_update(B) >>> A >>> A = 1, 2, 3, 4> >>> B = 2, 4> >>> A -= B >>> A
Неизменяемые множества
В Python существует неизменяемая версия множества — frozenset . Этот тип объектов поддерживает все операции обычного множества set , за исключением тех, которые его меняют.
Неизменяемые множества являются хешируемыми объектами, поэтому они могут быть элементами множества set . Так можно реализовать, например, множество множеств, где множество set состоит из множеств типа frozenset .
Для создания frozenset используется функция frozenset(iterable) , в качестве аргумента принимающая итерирумый объект.
>>> FS = frozenset(1, 2, 3>) >>> FS frozenset() >>> A = 1, 2, 4> >>> FS & A frozenset() >>> A & FS
В этом примере показано создание frozenset из обычного множества . Обратите внимание на тип возвращаемого объекта для операции пересечения & . Возвращаемый объект имеет тип, соответствующий типу первого аргумента. Такое же поведение будет и с другими операциями над множествами.
Словари Python
Словарь (dictionary) в Python — это ассоциативный массив, реализовать который вы пробовали на прошлом занятии. Ассоциативный массив это структура данных, содержащая пары вида ключ:значение. Ключи в ассоциативном массиве уникальны.
В Python есть встроенный ассоциативный массив — dict . Его реализация основана на хеш-таблицах. Поэтому
- ключом может быть только хешируемый объект
- значением может быть любой объект
Создание и изменение словаря
Пустой словарь можно создать двумя способами:
>>> d1 = dict() >>> d2 = <> >>> d1 <> >>> d2 <> >>> type(d1) >>> type(d2)
Добавить элемент в словарь можно с помощью квадратных скобок:
>>> domains = <> >>> domains[‘ru’] = ‘Russia’ >>> domains[‘com’] = ‘commercial’ >>> domains[‘org’] = ‘organizations’ >>> domains
Из этого примера видно, что литералом словаря являются фигурные скобки, в которых через запятую перечислены пары в формате ключ:значение . Например, словарь domains можно было создать так domains = .
Доступ к элементу осуществляется по ключу:
>>> domains['com'] 'commercial' >>> domains['de'] Traceback (most recent call last): File "", line 1, in KeyError: 'de'
Удалить элемент можно с помощью оператора del . Если ключа в словаре нет, произойдет ошибка KeyError
>>> domains >>> del domains[‘de’] Traceback (most recent call last): File «», line 1, in KeyError: ‘de’ >>> del domains[‘ru’] >>> domains
Кроме того, для добавления, получения и удаления элементов есть методы dict.setdefault , dict.get , dict.pop , которые задействует дополнительный аргумент на случай, если ключа в словаре нет
>>> d1 = <> >>> d1.setdefault(‘a’, 10) 10 >>> d1.setdefault(‘b’, 20) 20 >>> d1 >>> d1.setdefault(‘c’) >>> d1 >>> d1.setdefault(‘a’, 123) 10 >>> d1 >>> d1.get(‘a’) 10 >>> d1.get(‘d’) # вернул None >>> d1.get(‘d’, ‘NoKey’) ‘NoKey’ >>> d1.pop(‘d’) Traceback (most recent call last): File «», line 1, in KeyError: ‘d’ >>> d1.pop(‘d’, 255) 255 >>> d1 >>> d1.pop(‘a’, 255) 10 >>> d1
Примечание о числовых ключах
Ключом может являться и число: int или float . Однако при работе со словарями в Python помните, что два ключа разные, если для них верно k1 != k2 # True .
>>> d = 0: 10> >>> d >>> d[0] = 22 >>> d >>> d[0.0] = 33 >>> d >>> 0.0 != 0 False
Поэтому при возможности избегайте в качестве ключей float -объектов.
Использование DictView: циклы и множественные операции
Если попробовать пройтись в цикле по словарю, то это будет проход по ключам
>>> d = 'a': 10, 'c': 30, 'b': 20> >>> for k in d: . print(k) . a c b
Зачастую необходимо пройтись в цикле по ключам, значениям или парам ключ:значение, содержащиеся в словаре. Для этого существуют методы dict.keys() , dict.values() , dict.items() . Они возвращают специальные DictView объекты, которые можно использовать в циклах:
>>> d = 'a': 10, 'c': 30, 'b': 20> >>> for k in d.keys(): . print(k) . a c b >>> for v in d.values(): . print(v) . 10 30 20 >>> for k, v in d.items(): . print(k, v) . a 10 c 30 b 20
Объекты DictView , содержащие только ключи, ведут себя подобно множествам. Кроме того, если DictView объекты для значений или пар содержат неизменяемые объекты, тогда они тоже ведут себя подобно множествам. Это означает, что привычные для множеств операции пересечения, вхождения и другие также работают с DictView .
>>> d >>> dkeys = d.keys() >>> ‘abc’ in dkeys False >>> ‘c’ in dkeys True >>> ‘a’, ‘b’, ‘c’> == dkeys True >>> dkeys & ‘b’, ‘c’, ‘d’>
Словарь с упорядоченными ключами OrderedDict
Это может понадобится для отправки задач на ejudge.
Если внимательно просмотреть примеры на циклы выше, то видно, что порядок итерирования в циклах совпадает с порядком добавления элементов в словарь.
Однако, такое поведение у стандартных словарей dict гарантируется, начиная с версии 3.7 (лабораторные примеры были сделаны из-под версии 3.7.4). Узнать свою версию Python можно, например, из терминала python3 --version или зайдя в интерпретируемый режим (версия будет написана сверху).
Если для вашей программы важно упорядочивание элементов, но вы не знаете, какой версии интерпретатор будет исполнять ваш скрипт, то вам нужно воспользоваться упорядоченной версией словарей OrderedDict .
Она находится в стандартной библиотеке collections .
Упорядоченный словарь поддерживает все операции, что и обычный словарь.
>>> import collections >>> od = collections.OrderedDict() >>> od OrderedDict() >>> od['a'] = 10 >>> od['c'] = 30 >>> od['b'] = 20 >>> od OrderedDict([('a', 10), ('c', 30), ('b', 20)])
Сайт построен с использованием Pelican. За основу оформления взята тема от Smashing Magazine. Исходные тексты программ, приведённые на этом сайте, распространяются под лицензией GPLv3, все остальные материалы сайта распространяются под лицензией CC-BY.
Множества (Set)
Множество в Python — это коллекция неупорядоченных элементов. Каждый элемент множества должен быть уникальным, неизменяемым, и множества не хранят дублирующиеся элементы. Множества являются изменяемыми, что означает, что мы можем изменять их после создания.
В отличие от других коллекций в Python, к элементам множества не привязан индекс, то есть мы не можем напрямую обратиться к любому элементу множества по индексу. Однако мы можем напечатать их все вместе или получить список элементов, перебирая множество.
Создание множества в Python
Множество можно создать, заключив разделенные запятыми неизменяемые элементы в фигурные скобки <> . Python также предоставляет метод set() , который можно использовать для создания множества по переданной последовательности.
Пример 1: Использование фигурных скобок
Days = print(Days) print(type(Days)) print("looping through the set elements . ") for i in Days: print(i)
looping through the set elements . Friday Tuesday Monday Saturday Thursday Sunday Wednesday
Пример 2: Использование метода set()
Days = set(["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]) print(Days) print(type(Days)) print("looping through the set elements . ") for i in Days: print(i)
looping through the set elements . Friday Wednesday Thursday Saturday Monday Tuesday Sunday
Он может содержать элементы любого типа, такие как целое число, число с плавающей точкой, кортеж и т.д. Но изменяемые элементы (список, словарь, множество) не могут быть членами набора. Рассмотрим следующий пример.
# Creating a set which have immutable elements set1 = print(type(set1)) #Creating a set which have mutable element set2 = print(type(set2))
Traceback (most recent call last) in 4 5 #Creating a set which holds mutable elements ----> 6 set2 = 7 print(type(set2)) TypeError: unhashable type: 'list'
В приведенном выше коде мы создали два множества, множество set1 содержит неизменяемые элементы, а set2 — один изменяемый элемент в виде списка. При проверке типа set2 возникла ошибка, что означает, что set может содержать только неизменяемые элементы.
Создание пустого множества немного отличается, потому что пустые фигурные скобки <> также используются для создания словаря. Поэтому Python предоставляет метод set() , используемый без аргумента для создания пустого множества.
# Empty curly braces will create dictionary set3 = <> print(type(set3)) # Empty set using set() function set4 = set() print(type(set4))
Давайте посмотрим, что произойдет, если мы предоставим дублирующий элемент в множество.
set5 = print("Return set with unique elements:",set5)
Return set with unique elements:
В приведенном выше коде мы видим, что set5 состоял из нескольких дублирующихся элементов, когда мы напечатали его, мы удалили дубликаты из множества.
Добавление элементов в множество
Python предоставляет методы add() и update() , которые можно использовать для добавления определенного элемента в набор. Метод add() используется для добавления одного элемента, а метод update() — для добавления нескольких элементов в множество. Рассмотрим следующий пример.
Пример: 1 — Использование метода add()
Months = set(["January","February", "March", "April", "May", "June"]) print("\nprinting the original set . ") print(months) print("\nAdding other months to the set. "); Months.add("July"); Months.add ("August"); print("\nPrinting the modified set. "); print(Months) print("\nlooping through the set elements . ") for i in Months: print(i)
printing the original set . Adding other months to the set. Printing the modified set. looping through the set elements . February July May April March August June January
Чтобы добавить более одного элемента в набор, Python предоставляет метод update() . В качестве аргумента он принимает iterable .
Рассмотрим следующий пример.
Пример — 2 Использование функции update()
Months = set(["January","February", "March", "April", "May", "June"]) print("\nprinting the original set . ") print(Months) print("\nupdating the original set . ") Months.update(["July","August","September","October"]); print("\nprinting the modified set . ") print(Months);
printing the original set . updating the original set . printing the modified set .
Удаление элементов из набора
Python предоставляет метод discard() и метод remove() , которые можно использовать для удаления элементов из множества. Разница между этими функциями заключается в том, что при использовании функции discard() , если элемент не существует в наборе, то множество останется неизменным, в то время как метод remove() выдаст ошибку.
Рассмотрим следующий пример.
Пример-1 Использование метода discard()
months = set(["January","February", "March", "April", "May", "June"]) print("\nprinting the original set . ") print(months) print("\nRemoving some months from the set. "); months.discard("January"); months.discard("May"); print("\nPrinting the modified set. "); print(months) print("\nlooping through the set elements . ") for i in months: print(i)
printing the original set . Removing some months from the set. Printing the modified set. looping through the set elements . February March April June
Python также предоставляет метод remove() для удаления элемента из набора. Рассмотрим следующий пример удаления элементов с помощью метода remove() .
Пример-2 Использование функции remove()
months = set(["January","February", "March", "April", "May", "June"]) print("\nprinting the original set . ") print(months) print("\nRemoving some months from the set. "); months.remove("January"); months.remove("May"); print("\nPrinting the modified set. "); print(months)
printing the original set . Removing some months from the set. Printing the modified set.
Мы также можем использовать метод pop() для удаления элемента. Как правило, метод pop() всегда удаляет последний элемент, но набор неупорядочен, и мы не можем определить, какой элемент будет удален из множества.
Рассмотрим следующий пример удаления элемента из множества с помощью метода pop() .
Months = set(["January","February", "March", "April", "May", "June"]) print("\nprinting the original set . ") print(Months) print("\nRemoving some months from the set. "); Months.pop(); Months.pop(); print("\nPrinting the modified set. "); print(Months)
printing the original set . Removing some months from the set. Printing the modified set.
В приведенном выше коде последним элементом множества Month является March , но метод pop() удалил June и January , потому что набор неупорядочен и метод pop() не смог определить последний элемент набора.
Python предоставляет метод clear() для удаления всех элементов из набора.
Рассмотрим следующий пример.
Months = set(["January","February", "March", "April", "May", "June"]) print("\nprinting the original set . ") print(Months) print("\nRemoving all the items from the set. "); Months.clear() print("\nPrinting the modified set. ") print(Months)
printing the original set . Removing all the items from the set. Printing the modified set. set()
Разница между методами discard() и remove()
Несмотря на то, что метод discard() и remove() выполняют одну и ту же задачу, между discard() и remove() есть одно основное различие.
Если ключ, который нужно удалить из множества с помощью метода discard() , не существует в множестве, Python не выдаст ошибку. Программа сохраняет свой поток управления.
С другой стороны, если элемент, который нужно удалить из множества с помощью remove() , не существует в наборе, Python выдаст ошибку.
Рассмотрим следующий пример.
Months = set(["January","February", "March", "April", "May", "June"]) print("\nprinting the original set . ") print(Months) print("\nRemoving items through discard() method. "); Months.discard("Feb"); #will not give an error although the key feb is not available in the set print("\nprinting the modified set. ") print(Months) print("\nRemoving items through remove() method. "); Months.remove("Jan") #will give an error as the key jan is not available in the set. print("\nPrinting the modified set. ") print(Months)
printing the original set . Removing items through discard() method. printing the modified set. Removing items through remove() method. Traceback (most recent call last): File "set.py", line 9, in Months.remove("Jan") KeyError: 'Jan'
Операции с множествами в Python
С множеством можно выполнять такие математические операции, как объединение, пересечение, разность и симметричная разность. Python предоставляет возможность выполнять эти операции с помощью операторов или методов.
Объединение двух множеств в Python
Объединение двух множеств вычисляется с помощью оператора pipe ( | ). Объединение двух множеств содержит все элементы, которые присутствуют в обоих множествах.
Рассмотрим следующий пример для вычисления объединения двух множеств.
Пример 1: использование оператора union |
Days1 = Days2 = print(Days1|Days2) #printing the union of the sets
Python также предоставляет метод union() , который также можно использовать для вычисления объединения двух множеств. Рассмотрим следующий пример.
Пример 2: использование метода union()
Days1 = Days2 = print(Days1.union(Days2)) #printing the union of the sets
Пересечение двух множеств в Python
Пересечение двух множеств может быть выполнено с помощью оператора & или функции intersection() . Пересечение двух множеств задается как набор элементов, общих для обоих множеств.

Пример 1: Использование оператора &
Days1 = Days2 = print(Days1&Days2) #prints the intersection of the two sets
Пример 2: Использование метода intersection()
set1 = set2 = print(set1.intersection(set2)) #prints the intersection of the two sets
set1 = set2 = set3 = set1.intersection(set2) print(set3)
Метод intersection_update()
Метод intersection_update() удаляет из исходного множества элементы, которые не присутствуют в обоих множествах (во всех наборах, если задано несколько).
Метод intersection_update() отличается от метода intersection() , поскольку он изменяет исходное множество, удаляя ненужные элементы, с другой стороны, метод intersection() возвращает новое множество.
Рассмотрим следующий пример.
a = b = c = a.intersection_update(b, c) print(a)
Нахождение разности двух множеств в Python
Разность двух множеств можно вычислить с помощью оператора вычитания ( — ) или метода intersection() . Допустим, есть два множества A и B , а разность равна A-B , что означает, что в результирующем множестве будет получен тот элемент из A , которого нет в множестве B .

Пример 1: Использование оператора вычитания ( — )
Days1 = Days2 = print(Days1-Days2) #
Пример 2 : Использование метода difference()
Симметричная разность двух множеств в Python
Симметричная разность двух множеств вычисляется с помощью оператора ^ или метода symmetric_difference() . Симметричная разность множеств, удаляет тот элемент, который присутствует в обоих множествах. Рассмотрим следующий пример:

Пример — 1: Использование оператора ^
a = b = c = a^b print(c)
Пример — 2: Использование метода symmetric_difference()
a = b = c = a.symmetric_difference(b) print(c)
Сравнение множеств
Python позволяет нам использовать операторы сравнения, т.е. < , >, = , == с множествами, с помощью которых мы можем проверить, является ли множество подмножеством, супермножеством или эквивалентным другому множеству. В зависимости от элементов, присутствующих внутри множества, возвращается булево значение true или false .
Рассмотрим следующий пример.
Days1 = Days2 = Days3 = #Days1 is the superset of Days2 hence it will print true. print (Days1>Days2) #prints false since Days1 is not the subset of Days2 print (Days1
True False False
Замороженные множества (FrozenSets) в Python
Замороженные множества являются неизменяемой формой обычных множеств, то есть элементы замороженного множества не могут быть изменены и поэтому могут быть использованы в качестве ключа в словаре.
Элементы замороженного множества не могут быть изменены после создания. Мы не можем изменять или добавлять содержимое замороженных наборов с помощью таких методов, как add() или remove() .
Метод frozenset() используется для создания объекта frozenset. В этот метод передается итерируемая последовательность, которая преобразуется в замороженный набор в качестве возвращаемого типа метода.
Для создания замороженного набора рассмотрим следующий пример.
Frozenset = frozenset([1,2,3,4,5]) print(type(Frozenset)) print("\nprinting the content of frozen set. ") for i in Frozenset: print(i); Frozenset.add(6) #gives an error since we cannot change the content of Frozenset after c
printing the content of frozen set. 1 2 3 4 5 Traceback (most recent call last): File "set.py", line 6, in Frozenset.add(6) #gives an error since we can change the content of Frozenset after creation AttributeError: 'frozenset' object has no attribute 'add'
Замороженные множества (FrozenSets) для словаря
Если передать словарь в качестве последовательности в метод frozenset() , то он возьмет только ключи из словаря и вернет frozenset, который содержит ключи словаря в качестве своих элементов.
Рассмотрим следующий пример.
Dictionary = print(type(Dictionary)) Frozenset = frozenset(Dictionary); #Frozenset will contain the keys of the dictionary print(type(Frozenset)) for i in Frozenset: print(i)
Name Country ID
Примеры мрограмм с использование множеств
Пример - 1: Напишите программу для удаления заданного числа из набора.
my_set = n = int(input("Enter the number you want to remove")) my_set.discard(n) print("After Removing:",my_set)
Enter the number you want to remove:12 After Removing:
Пример - 2: Напишите программу для добавления нескольких элементов к множеству.
set1 = set([1,2,4,"John","CS"]) set1.update(["Apple","Mango","Grapes"]) print(set1)
Пример - 3: Напишите программу для нахождения объединения двух множеств.
set1 = set(["Peter","Joseph", 65,59,96]) set2 = set(["Peter",1,2,"Joseph"]) set3 = set1.union(set2) print(set3)
Пример - 4: Напишите программу для нахождения пересечения двух множеств.
set1 = set2 = set3 = set1.intersection(set2) print(set3)
Пример - 5: Напишите программу для добавления элемента в морозильную установку.
set1 = set2 = set3 = set1.intersection(set2) print(set3)
TypeError: 'frozenset' object does not support item assignment
Вышеприведенный код вызвал ошибку, так как замороженные множества неизменяемы и не могут быть изменены после создания.
Пример - 6: Напишите программу для нахождения issuperset, issubset и superset.
set1 = set(["Peter","James","Camroon","Ricky","Donald"]) set2 = set(["Camroon","Washington","Peter"]) set3 = set(["Peter"]) issubset = set1 >= set2 print(issubset) issuperset = set1 = set3 print(issuperset)
False False True True
Встроенные методы множеств в Python
Python содержит следующие методы для использования с множествами.
| Метод | Описание |
|---|---|
| add(item) | Добавляет элемент в множество. Не имеет эффекта, если элемент уже присутствует в множестве. |
| clear() | Удаляет все элементы из множества. |
| copy() | Возвращает неглубокую копию множества. |
| difference_update(. ) | Изменяет множество, удаляя все элементы, которые также присутствуют в других указанных множествах. |
| discard(item) | Удаляет указанный элемент из множества. |
| intersection() | Возвращает новое множество, содержащее только общие элементы обоих множеств. (всех множеств, если указано более двух). |
| intersection_update(. ) | Удаляет элементы из исходного множества, которые не присутствуют в обоих множествах (во всех множествах, если указано несколько). |
| isdisjoint(. ) | Возвращает True , если два множества имеют нулевое пересечение. |
| issubset(. ) | Сообщает, содержит ли другое множество указанный набор. |
| issuperset(. ) | Сообщает, содержит ли указаннное множество другой набор. |
| pop() | Удаляет и возвращает произвольный элемент множества, который является последним элементом множества. Вызывает KeyError , если множество пустое. |
| remove(item) | Удаляет элемент из множества; он должен быть его членом. Если элемент не является членом множества, то возвращает KeyError . |
| symmetric_difference(. ) | Возвращется элементы, которые есть в двух множествах (в одном или другом, но не в обоих) |
| symmetric_difference_update(. ) | Возвращает новое множество, содержащее симметричную разность двух множеств. |
| union(. ) | Возвращает объединение множеств в виде нового множества (т.е. все элементы, которые есть в любом из множеств). |
| update() | Выполняет объединение всех задействованных множеств и обновляет множество, для которого он вызывается. Он добавляет все члены набора аргументов в множеств, для которого он вызывается. |
Исчерпывающее руководство по множествам в Python
Класс set (множество) — это одна из ключевых структур данных в Python. Она представляет собой неупорядоченную коллекцию уникальных элементов. Класс set , в некоторой степени, соответствует математическому множеству. Многие широко используемые математические операции, применимые к множествам, существуют и в Python. Часто вычисления, производимые над множествами, оказываются гораздо быстрее, чем альтернативные операции со списками. В результате, для того чтобы писать эффективный код, Python-программисту просто необходимо уметь пользоваться множествами. В этой статье я расскажу об особенностях работы с классом set в Python.

Инициализация множеств
Существует два способа создания объекта set : с использованием конструкции set(iterable) и путём помещения элементов, разделённых запятыми, в фигурные скобки — < . >. Если же при инициализации множества попытаться воспользоваться пустыми фигурными скобками — <> — тогда будет создан словарь, а не пустое множество. Для создания пустых множеств используется команда set() . Обратите внимание на то, что при инициализации множеств порядок элементов неважен, и на то, что дублирующиеся элементы в множество добавить не получится.
a = < "a", "b", "c", "d", "e", "f", "f" ># конструктору set можно передать любой итерируемый объект b = set(["a", "b", "c", "d", "e", "f"]) c = set(("a", "b", "c", "d", "e", "e", "f", "f")) # порядок элементов неважен d = set(["d", "e", "f", "a", "b", "c"]) # деструктурирование списка e = < *["a", "b", "c", "d", "e", "f"] >assert a == b == c == d == e # в одном множестве могут храниться значения разных типов f = set(["a", True, 123]) g = < "a", True, 123, True, 123 >assert f == g # set() - это множество, а <> - это словарь assert set() != <>
Какие элементы можно включить в состав множества? Это могут быть только элементы иммутабельных типов. Сюда входят такие типы, как float , int , string , bool и прочие подобные. А вот мутабельные типы — списки, словари, да и сами множества, в состав множеств включать нельзя. Если вас интересуют подробности о типах данных в Python — рекомендую почитать эту статью. Учитывая вышесказанное — следующая конструкция вызовет ошибку:
< ["a", "b", "c"], True ># => TypeError: unhashable type: 'list'
Но что если случается так, что в множествах надо хранить некие уникальные последовательности значений? Подробнее об этом мы поговорим в конце статьи.
Примечание об иммутабельности
Иммутабельность — это ограничение, касающееся лишь встроенных типов. На практике, чтобы объект можно было добавить в множество, или чтобы его можно было использовать в качестве ключа в словаре, этот объект всего лишь должен быть хешируемым. По умолчанию объекты пользовательских классов обладают хешем, основанным на их идентификаторах. Равенство объектов определяется по их идентификаторам. Это значит, что два объекта, идентичные в плане атрибутов, будут равны друг другу только тогда, когда они представляют один и тот же объект, или в том случае, если для них определён пользовательский оператор eq .
Если для некоего класса определён пользовательский оператор eq , то объекты этого класса перестают быть хешируемыми, если только для них не будет определён пользовательский оператор hash . Тут важно то, что если два объекта равны, то их хеши тоже должны быть равны. В противном случае при добавлении подобных объектов в словарь или в множество возникнут проблемы. Дело в том, что при проверке наличия значения в составе ключей словаря или в составе множества, проверяются и хеши и равенство объектов.
Единственный случай, когда в множестве имеет смысл хранить мутабельный объект, или когда такой объект может играть роль ключа словаря, это когда оператор проверки равенства объекта не использует его мутабельные атрибуты. Предположим, у некоего объекта имеется оператор равенства и соответствующая хеш-функция, основанные на атрибутах этого объекта. Если такой объект сначала добавить в множество, а потом поменять его, тогда хеш-значение, использованное при его сохранении, будет отличаться от текущего хеш-значения. Это — плохая практика.
Добавление элементов в множества
Существует множество способов добавления элементов в множество. Для того чтобы осуществить изменение (мутацию) множества, отдельный элемент в него можно добавить командой .add() . Итерируемый объект добавляют командой .update() , или, что то же самое, используя оператор |= :
a = set() # добавление строкового элемента a.add("hello") # Следующий код НЕ эквивалентен предыдущему. # Метод update ожидает поступления итерируемого объекта, поэтому # строка рассматривается как итерируемый объект, содержащий символы # которые и добавляются в множество a.update("hello") assert a == < 'hello', 'h', 'e', 'l', 'o' ># А тут в множество добавляются две строки, так как они размещены в списке a.update(["hi", "world"]) assert a ==
Под «мутацией» я понимаю изменение исходного объекта. Есть ещё команды, которые не изменяют исходное множество. Например — метод . union() , или его эквивалент — оператор | :
a = < "a", "b" , "c" >b = < "a", "c", "d" >assert a | b == a.union(b) == < "a", "b", "c", "d" ># исходные объекты не изменились assert a == < "a", "b" , "c" >and b ==
Явное различие поведения методов .update() и .union() можно продемонстрировать, разобрав следующий пример:
def add_to_set1(a, b): a.update(b) return a def add_to_set2(a, b): a = a.union(b) return a a = < "a", "b" , "c" >b = < "a", "c", "d" ># Исходный объект был модифицирован # и будет равен возвращённому объекту assert a == add_to_set1(a, b) a = < "a", "b" , "c" >b = < "a", "c", "d" ># Исходный объект НЕ был модифицирован # и не будет равен возвращённому объекту assert a != add_to_set2(a, b)
И наконец — два множества можно конкатенировать, использовав деструктурирование:
a = < "a", "b" , "c" >b = < "a", "c", "d" >assert < *a, *b >==
Этот приём будет работать аналогично методу .union() , но я рекомендую пользоваться именно .union() .
Обратите внимание на то, что в предыдущих примерах я пользовался методом .update() , но в них можно было бы применить и оператор |= . Это значит, что a |= b ( .update() ) — это НЕ то же самое, что a = a | b (.union()) . Дело в том, что в первом фрагменте кода осуществляется изменение объекта, хранящегося в a , а во втором примере a назначается новое значение.
Удаление элементов множеств
Мы рассмотрели команды для добавления элементов в множества. Существуют похожие на них команды, применяемые при удалении элементов. Вот как эти команды можно соотнести с уже известными вам командами:
- Аналог .add() — .remove() .
- Аналог .update() — .difference_update() или -= .
- Аналог .union() — .difference() или - .
a = < "a", "b" , "c" >a.remove("b") assert a == < "a", "c" >a = < "a", "b" , "c" ># Так же, как .update(), эта команда ожидает итерируемый объект # В результате здесь удаляются "a" и "b", # а не целая строка "ab" a.difference_update("ab") assert a == < "c" >a = < "a", "b" , "c" >a.difference_update(["ab"]) # "ab" нет в составе элементов множества, поэтому ничего не удаляется assert a == < "a", "b", "c" ># Оператор -, эквивалент метода .difference(), # не модифицирует исходный объект a = < "a", "b" , "c" >b = a - < "b", "c" >assert a != b and b ==
Снова хочу обратить ваше внимание на то, что надо помнить о разнице между конструкциями вида a -= b (исходное множество изменяется) и a = a — b (исходное множество не изменяется).
Имеется и ещё несколько методов, которые могут пригодиться для удаления объектов:
- .clear() — очищает множество.
- .remove() — удаляет элемент лишь в том случае, если он существует (в противном случае выдаёт ошибку); .discard() — работает похожим образом, но, если элемента не существует, ошибку не возвращает.
- .pop() — удалит случайный элемент из множества и вернёт этот элемент.
Другие операции для работы с множествами
Одна из сильных сторон Python-множеств заключается в наличии большого количества стандартных операций, предназначенных для работы с ними. Мы обсудили команды для модификации множеств путём добавления и удаления элементов, но это — далеко не всё, что можно делать с множествами.
Пересечение множеств
Пересечением двух множеств является множество элементов, входящих в состав обоих множеств. Для выполнения этой операции используются следующие методы и операторы:
- Команды, при выполнении которых множество не меняется: .intersection() или & . Например — a.intersection(b) или a & b .
- Команды, при выполнении которых множество меняется: .intersection_update() или &= .
a = < "a", "b", "c" >b = < "b", "c", "d" >assert a & b ==
Симметрическая разность множеств или дизъюнктивное объединение
Симметрическая разность множеств — это противоположность их пересечению. Она даёт все элементы, которые не принадлежат одновременно обоим исходным множествам. Для нахождения симметрической разности множеств используются следующие методы и операторы:
- Команды, при выполнении которых множество не меняется: . symmetric_difference() или ^ . Например — a.symmmetric_difference(b) или a ^ b .
- Команды, при выполнении которых множество меняется: .symmetric_difference_update() или ^= .
a = < "a", "b", "c" >b = < "b", "c", "d" >assert a ^ b ==
Методы проверки наличия элементов в множествах, сравнение множеств
Я рассказал о том, как модифицировать множества, но они, в основном, используются для того, чтобы быстро проверять, имеются ли в них некие элементы, или нет. Подобные операции, выполняемые на списках, будут медленнее. Посмотрим на конструкции, используемые для проверки наличия элементов в множествах, и на некоторые другие полезные команды.
Проверка принадлежности элемента множеству
Вероятно, это — та операция, к которой вы будете прибегать чаще, чем к другим. Проверка наличия элемента в множестве выполняется с помощью оператора in . А проверка отсутствия элемента — с помощью оператора not in . Для таких операций над множествами, в отличие от подобных проверок, выполняемых в применении к спискам, характерна константная временная сложность — O(1). В результате, по мере роста размеров множества, не будет страдать скорость проверки наличия или отсутствия в нём неких элементов.
a = < "a", "b", "c" >assert "a" in a assert "d" not in a
Проверка того, является ли одно множество подмножеством другого
Множество является подмножеством другого множества в том случае, если все элементы первого множества входят в состав второго. Например, (A, B, C) — это подмножество (A, B, C, D) . В Python подобную проверку можно провести, воспользовавшись методом .issubset() или оператором = и > .
a = < "a", "b", "c" >b = < "a", "b" >assert a.issubset(b) == (a = b and a > b
Проверка того, что в двух множествах нет общих элементов
Если в множествах нет общих элементов, их называют непересекающимися множествами. В Python соответствующая проверка выполняется с помощью метода .isdisjoint() .
a = < "a", "b", "c" >b = < "a", "b" >c = < "d" ># без isdisjoint() assert len(a & c) == 0 and len(a & b) != 0 # с этим методом assert a.isdisjoint(c) and not a.isdisjoint(b)
Абстракция множеств
Так же, как и в случае со списками и словарями, при работе с множествами можно воспользоваться так называемой абстракцией множеств (set comprehension). Делается это путём добавления обрабатываемого выражения в фигурные скобки и через возврат единственного мутабельного элемента на каждом проходе цикла: < for . in . > .
# преобразование списка в множество с добавлением 1 к каждому элементу assert < i+1 for i in [1, 2, 3, 4] >== < 2, 3, 4, 5 ># только чётные числа a = < i for i in range(10) if i % 2 == 0 >a.update(< -3, 100 >) # Преобразование множества в список с добавлением 1 к каждому элементу # ВНИМАНИЕ: перебирая множество, не рассчитывайте на то, что сохранится тот # порядок следования элементов, в котором они были в него добавлены print([i+1 for i in a]) # => [1, 3, 5, 101, 7, 9, -2]
Хранение в множествах данных более сложных типов
Представьте, что у нас имеется цикл, на каждой итерации которого мы обходим некоторое количество узлов графа. Предположим, мы обошли граф два раза, у нас получились следующие пути:
A -> B -> D D -> C -> E -> B
Потом надо быстро проверить, прошлись ли мы по определённому пути. Нужно, чтобы такая проверка проводилась бы быстро, поэтому совершенно естественным будет использовать для её реализации множество. Как это сделать, если список, из-за его мутабельности, нельзя добавить в множество? К нашему счастью, в подобных обстоятельствах можно воспользоваться кортежем, классом tuple , который, по сути, представляет собой иммутабельную версию списка. Рассмотрим пример.
Сначала создадим граф, используя словарь. Ключи словаря будут представлять узлы графа, а значения — списки узлов, в которые можно перейти из текущего узла.
# можно перейти от ключа к значениям graph =
Визуализировав это описание, я получил такой граф.

Если вы задаётесь вопросом о том, как я создал такой граф — знайте, что сделал я это, прибегнув к graphviz и написав следующий код:
from graphviz import Digraph dot = Digraph() for k in graph.keys(): dot.node(k, k) edges = [] for k, v in graph.items(): edges += [f"" for to in v] dot.edges(edges) dot.render(view=True)
Теперь я займусь случайным блужданием по графу, проходя от 1 до 10 узлов, после чего сохраню результирующие пути в объекте set в виде кортежей. Посмотрим, сколько уникальных путей мы сможем сгенерировать за 100 проходов по графу:
import random def perform_random_walk(graph, n_steps): node = random.sample(list(graph), 1)[0] path = [node] for _ in range(n_steps): node = random.sample(graph[node], 1)[0] path.append(node) return tuple(path) paths = set() lengths = list(range(1, 10+1)) for _ in range(100): paths.add(perform_random_walk(graph, random.choice(lengths))) len(paths) # => 83
Из 100 случайных проходов по графу 83 оказались уникальными.
А что если нас не волнует порядок узлов, а нужно лишь сохранить сведения о посещённых узлах? Тогда будет смысл хранить отдельные пути в множествах, но, как уже было сказано, множества мутабельны, помещать их в другие множества нельзя. В такой ситуации, вместо обычных множеств, описываемых классом set , можно прибегнуть к неизменяемым множествам, представленным классом frozenset . Чтобы это сделать — поработаем с кодом цикла из предыдущего примера:
paths = set() lengths = list(range(1, 10+1)) for _ in range(100): path = perform_random_walk(graph, random.choice(lengths)) paths.add(frozenset(path)) len(paths) # => 21
Итоги
Множества — это полезный инструмент Python-разработчика. Они позволяют очень быстро выполнять определённые операции, что способно значительно повысить эффективность кода. Кроме того, в Python имеется немало простых и полезных методов для работы с множествами, применение которых способствует упрощению кода.
О, а приходите к нам работать?
Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.
Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.
Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.
Множества в Python
Множество — неупорядоченный набор элементов. Каждый элемент в множестве уникален (т. е. повторяющихся элементов нет) и неизменяем.
Само по себе множество можно изменять, то есть удалять или добавлять элементы.
Множества удобно использовать для выполнения математических операций: объединение, пересечение, симметрическая разность и т. д.
Как создать множество
Множество объявляется так: элементы помещаются в фигурные скобки <> и разделяются запятыми. Сделать это можно и с помощью встроенной функции set() .
Внутри множества может быть любое количество элементов любого типа (целые числа, числа с плавающей точкой, кортежи, строки и т. д.). Внутрь множества нельзя помещать элементы изменяемых типов: списки, другие множества или словари.
# Разные виды множеств # Множество с целыми числами my_set = print(my_set) # Множество с разными типами данных my_set = print(my_set)
Вывод:
# Внутри множества не может быть одинаковых элементов # Вывод: my_set = print(my_set) # Аргументом функции set() может быть список # Вывод: my_set = set([1, 2, 3, 2]) print(my_set) # Внутри множества не может быть изменяемых объектов # В этом множестве [3, 4] — изменяемый список # Поэтому следующая строка вызовет ошибку my_set =
Вывод:
Traceback (most recent call last):
File "", line 15, in
my_set =
TypeError: unhashable type: 'list'
Создание пустого множество — дело хитрое.
Пустые фигурные скобки <> — это словарь. Чтобы объявить пустое множество, нужно использовать функцию set() без аргументов.
# Обратим внимание на объявление пустого множества # Объявление с помощью <> a = <> # Проверка типа a print(type(a)) # Объявление с помощью set() a = set() # Проверка типа a print(type(a))
Вывод:
Как изменять множество
Множества изменяемы и не упорядочены. Поэтому в индексации нет никакого смысла.
Так что получить доступ к элементам с помощью индексов или срезов не получится. Множества просто не поддерживают эти операции.
Чтобы добавить один элемент, нужно использовать метод add() . Если нужно добавить несколько элементов — метод update() . Метод update() принимает в качестве аргументов кортежи, списки или другие множества. Во всех случаях следует избегать одинаковых элементов.
# создаем my_set my_set = print(my_set) # вызов my_set[0] приведет к ошибке # TypeError: 'set' object does not support indexing # добавляем элемент # Вывод: my_set.add(2) print(my_set) # добавляем несколько элементов # Вывод: my_set.update([2, 3, 4]) print(my_set) # добавляем список и множество # Вывод: my_set.update([4, 5], ) print(my_set)
Вывод:
Как удалять элементы из множества
Определенный элемент множества можно удалить с помощью методов discard() и remove() .
Разница между ними вот в чем. Если элемент, который вы хотите удалить с помощью discard() , отсутствует в множестве — оно не изменится. А вот remove() вызовет ошибку, если элемента нет в множестве.
# разница между discard() и remove() # создаем my_set my_set = print(my_set) # удаление элемента # с помощью discard # Вывод: my_set.discard(4) print(my_set) # удаление элемента # с помощью remove # Вывод: my_set.remove(6) print(my_set) # удаление элемента, # отсутствующего в my_set, # с помощью discard # Вывод: my_set.discard(2) print(my_set) # При удалении элемента, # отсутствующего в my_set, # с помощью remove # вы получите ошибку. # Вывод: KeyError my_set.remove(2)
Вывод:
Traceback (most recent call last):
File "", line 28, in
KeyError: 2
Удалить и вернуть элемент мы можем с помощью метода pop() .
Так как множество — неупорядоченный тип данных, невозможно определить, какой из элементов будет удален. Это произойдет случайным образом.
Удалить все элементы из множества можно с помощью метода clear() .
# cоздаем my_set # Вывод: множество уникальных элементов my_set = set("Приветмир") print(my_set) # pop элемента # Вывод: случайный элемент print(my_set.pop()) # pop еще одного элемента my_set.pop() print(my_set) # очищаем my_set # Вывод: set() my_set.clear() print(my_set)
Вывод:
П
set()
Операции со множествами
Множества можно использовать для выполнения математических операций вроде объединения, пересечения, симметрической разности и т. д. Сделать это можно с помощью операторов и методов.
Рассмотрим два множества и проведем с ними разные операции.
A =
B =
Объединение
Результат бъединения A и B — множество, содержащее в себе все элементы множеств A и B.
Операцию объединения можно произвести двумя способами: с помощью оператора | и метода union() .
# Операция объединения двух множеств # Создаем множества A и B A = B = # Используем оператор | # Вывод: print(A | B)
Вывод:
Попробуйте ввести следующие примеры в консоль:
# используем функцию union >>> A.union(B) # используем функцию union с B >>> B.union(A)
Пересечение
Результат пересечения A и B — множество, которому принадлежат те и только те элементы, которые одновременно принадлежат всем данным множествам
Операцию объединения можно произвести двумя способами: с помощью оператора & и метода intersection() .
# Пересечение множеств # Создаем множества A и B A = B = # Используем оператор & # Вывод: print(A & B)
Вывод:
Попробуйте ввести следующие примеры в консоль:
# использование метода intersection с A >>> A.intersection(B) # использование метода intersection с B >>> B.intersection(A)
Разность
Результат разности множеств B и A — множество элементов, содержащихся только в A. Следовательно, B-A = множество элементов, содержащихся только в B.
Операцию объединения можно произвести двумя способами: с помощью оператора - и метода difference() .
# Разность двух множеств # Создаем множества A и B A = B = # Используем оператор - с A # Вывод: print(A - B)
Вывод:
Попробуйте ввести следующие примеры в консоль:
# Использование функции difference с A >>> A.difference(B) # Использование оператора - с B >>> B - A # Использование функции difference с B >>> B.difference(A)
Симметрическая разность
Результат симметрической разности множеств A и B — множество элементов, содержащихся и в A, и в B, но не в обоих сразу. Иначе говоря, исключается только пересечение множеств.
Операцию объединения можно произвести двумя способами: с помощью оператора ^ и метода symmetric_difference() .
# Симметрическая разность множеств A и B # Создаем множества A и B A = B = # Используем оператор ^ # Вывод: print(A ^ B)
Вывод:
Попробуйте ввести следующие примеры в консоль:
# Использование функции symmetric_difference с A >>> A.symmetric_difference(B) # Использование функции symmetric_difference с B >>> B.symmetric_difference(A)
Методы множеств
У множеств много методов, некоторые мы уже обсудили выше. Вот полный список методов объекта set :
Метод
Описание
Добавляет элемент в множество
Удаляет все элементы из множества
Возвращает копию множества
Возвращает новое множество — разность двух или более множеств
Удаляет все элементы одного набора из другого
Удаляет элемент, если он содержится в множестве (если элемента в множестве нет, то ничего не происходит)
Возвращает новое множество — пересечение двух множеств
Добавляет в множество пересечение с другим множеством или с самим собой
Возвращает True , если два множества не имеют пересечения
Возвращает True , если определенное множество содержится в другом множестве
Возвращает True , если в множестве есть другое множество
Удаляет и возвращает случайный элемент множества. Если множество пусто, то возвращает ошибку KeyError
Удаляет определенный элемент множества. Если элемент отсутствует в множестве, то возвращает ошибку KeyError
Возвращает новое множество — симметрическую разность двух множеств
Добавляет в множество симметрическую разницу с другим множеством или с самим собой
Возвращает новое множество — объединение множеств
Добавляет в множество объединение с другим множеством или с самим собой
Несколько операций со множествами
Проверка на вхождение
Мы можем проверить, есть ли элемент в множестве. Сделать это можно с помощью ключевого слова in .
# Использование ключевого слова in # Создаем множество my_set my_set = set("яблоко") # Проверяем, есть ли 'о' в множестве # Вывод: True print('о' in my_set) # Проверяем, отсутствует ли 'к' в множестве # Output: False print('к' not in my_set)
Вывод:
True
False
Итерирование по множеству
Множество можно перебрать с помощью цикла for .
for letter in set("яблоко"): print(letter)
Вывод:
я
о
л
к
б
Встроенные функции множеств
Функция
Описание
Возвращает True , если все элементы множества истинны или множество пустое
Возвращает True , если хоть один элемент множества истинен. Если множество пустое, возвращает False
Возвращает перечисляемый объект. В нем в виде пар содержатся значения и индексы всех элементов множества
Возвращает длину (количество элементов) множества
Возвращает наибольший элемент множества
Возвращает наименьший элемент множества
Возвращает отсортированный список, в котором находятся элементы множества (само множество не сортируется)
Возвращает сумму всех элементов множества
Frozenset
Frozenset — класс, имеющий характеристики множества. Отличие состоит в том, что frozenset после объявления неизменяем.
Кортеж — неизменяемый список, frozenset — неизменяемое множество.
Множества изменяемы, поэтому не могут использоваться в качестве ключей словаря. Frozenset же неизменяемы — их можно использовать в качестве ключей словаря.
Этот тип данных поддерживает следующие методы: copy() , difference() , intersection() , isdisjoint() , issubset() , issuperset() , symmetric_difference() и union() . Так как он неизменяем, методы add() и remove() с ним не работают.
# Frozenset # Создаем множества A и B A = frozenset([1, 2, 3, 4]) B = frozenset([3, 4, 5, 6])
Попробуйте ввести следующие примеры в консоль:
>>> A.isdisjoint(B) False >>> A.difference(B) frozenset() >>> A | B frozenset() >>> A.add(3) . AttributeError: 'frozenset' object has no attribute 'add' ```
