okpython.net
Все для начинающих

Множества в Python

Понятие множества в Python

Для хранения наборов уникальных объектов в Python был введен еще один тип данных, называемый «множества».

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

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

Создание множеств в Python

Для того, чтобы в Python создать литерал множества, нужно просто перечислить элементы множества через запятую внутри фигурных скобок (см. пример №1). При этом последний элемент множества также разрешается завершать запятой, поскольку это никак не повлияет на количество элементов в нем.

Код Результат pythonCodes
# Множество из одного эл-та.
s_1 = {1}
print(s_1, end='\n\n')		

# Множество из 3-х эл-тов.
s_2 = {'a', 0.1, ('b', 2)}
print(s_2, end='\n\n')		
			
# Вывело {1, 'a'}.
s_3 = {'a', 1, 1}
print(s_3, end='\n\n')			

# unhashable type: 'list'
s_1 = {'a', 0.1, ['b', 2]}	
{1}

{0.1, 'a', ('b', 2)}

{1, 'a'}

unhashable type: 'list'





		
			

Пример №1. Создание множеств в Python (часть 1).

Как видим, множества действительно состоят из наборов неизменяемых уникальных значений. Если попытаться добавить в множество изменяемый элемент, интерпретатор выдаст ошибку. Попытка создания множества с несколькими одинаковыми элементами ошибки не вызовет, но интерпретатор преобразует его так, чтобы в нем остался только один из одинаковых элементов. Также при помощи фигурных скобок не получится создать пустое множество, ведь конструкция {} зарезервирована под пустой словарь.

Однако создать пустое множество можно при помощи встроенного конструктора типа set([iterable]), который в качестве аргумента может принимать итерируемый объект, например, строку или список. Если использовать конструктор без аргумента, он как раз и вернет нам пустое множество set(). Если же использовать конструктор с аргументом, он вернет нам множество с элементами переданного итерируемого объекта (см. пример №2).

Код Результат pythonCodes
# Пустое множество.
s_0 = set()
print(s_0, end='\n\n')			

# Мн-во с 1 эл-том (запятая обязательна).
s_1 = set((1,))
print(s_1, end='\n\n')		

# Множество из 3-х эл-тов.
s_2 = set(('a', 0.1, ('b', 2)))
print(s_2, end='\n\n')		
			
# Вывело {1, 'a'}.
s_3 = set(('a', 1, 1))
print(s_3, end='\n\n')			
			
# Получаем поверхностную копию мно-ва.
s_4 = set(s_3)
print(s_4, end='\n\n')

# unhashable type: 'list'
s_5 = set(('a', 0.1, ['b', 2]))
set()

{1}

{0.1, ('b', 2), 'a'}

{1, 'a'}

{1, 'a'}

unhashable type: 'list'
 
 
 






		
			

Пример №2. Создание множеств в Python (часть 2).

Обратите внимание, что если передать конструктору другое множество, он вернет его поверхностную копию. Также имейте в виду, что при передаче конструктору кортежа с одним элементом нужно использовать завершающую запятую, чтобы интерпретатор мог отличить кортеж от простого выражения.

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

Код Результат pythonCodes
# Генерируем множество из строки.
s_1 = {simb for simb in '123'}
# У меня вывело {'3', '2', '1'}.
print(s_1, end='\n\n')

# Используем более сложное выражение.
s_2 = {int(num)*5 for num in '123'}
# У меня вывело {10, 5, 15}.
print(s_2)
{'3', '2', '1'}

{10, 5, 15}




		
			

Пример №3. Создание множеств в Python (часть 3).

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

При использовании для создания множеств любого из перечисленных методов важно помнить, что будущие элементы множества должны быть неизменяемыми. Можно, например, использовать числа, строки, логические значения True и False, объект None или кортеж, состоящий из неизменяемых элементов. Но использовать словари или списки в качестве элементов множества не получится.

Операторы множеств в Python

Поскольку множества, как и словари, относятся к неупорядоченным коллекциям объектов, операторы +, +=, * и *= с ними не используются. Однако множествам доступен целый ряд других математических операторов:

  • s_1 >= s_2 – возвращает True, если множество s_1 является надмножеством s_2, т.е. каждый элемент второго множества есть в первом множестве (см. пример №4);
  • s_1 > s_2 – возвращает True, если множество s_1 является надмножеством s_2 и при этом они не равны (поэтому, например, проверка {1, 2} > {1, 2} вернет False);
  • s_1 <= s_2 – возвращает True, если множество s_1 является подмножеством s_2, т.е. каждый элемент первого множества есть во втором множестве;
  • s_1 < s_2 – возвращает True, если множество s_1 является подмножеством s_2 и при этом они не равны (поэтому, например, проверка {1, 2} < {1, 2} вернет False);
  • s_1 | s_2 – возвращает новое множество, образуемое через объединение множеств (такое множество состоит из всех элементов, которые есть хотя бы в одном из множеств, участвующих в операции);
  • s_1 |= s_2 – обновляет множество s_1, добавляя элементы из множества s_2;
  • s_1 & s_2 – возвращает новое множество, образуемое через пересечение множеств (такое множество состоит из всех элементов, которые есть сразу в обоих множествах, участвующих в операции);
  • s_1 &= s_2 – обновляет множество s_1, оставляя в нем только элементы, которые есть сразу в обоих множествах, участвующих в операции;
  • s_1 - s_2 – возвращает новое множество, образуемое через разность множеств (такое множество состоит из всех элементов, которые есть в уменьшаемом множестве (левый операнд), но нет в вычитаемом множестве (правый операнд));
  • s_1 -= s_2 – обновляет множество s_1, оставляя в нем только элементы, которых нет в множестве s_2;
  • s_1 ^ s_2 – возвращает новое множество, образуемое через симметричную разность множеств (такое множество состоит из всех элементов, которые есть в одном из множеств, участвующих в операции, но не в обоих сразу).
  • s_1 ^= s_2 – обновляет множество s_1, оставляя в нем только элементы, которые есть в одном из множеств, участвующих в операции, но не в обоих сразу.
Код Результат pythonCodes
# Сохраняем множества в переменных.
s_1 = {1, 2}
s_2 = {1, 2, 3}
				
# Вернет True.
print('s_1 < s_2 ->', s_1 < s_2)
# Вернет False.
print('s_1 > s_2 ->', s_1 > s_2, end='\n\n')		

# Получаем новые мн-ва, исх. не изменяются.

# Пересечение: {1, 2}.
print('s_1 & s_2 ->', s_1 & s_2)		
# Объединение: {1, 2, 3}.
print('s_1 | s_2 ->', s_1 | s_2)		
# Разность: set(), т.е. пустое мн-во.
print('s_1 - s_2 ->', s_1 - s_2)		
# Сим. разность: {3}.
print('s_1 ^ s_2 ->', s_1 ^ s_2, end='\n\n')

# Здесь изменяется мн-во s_1.		
		
# Теперь s_1 == {1, 2}.
s_1 &= s_2
print('s_1 &= s_2 ->', s_1)		
# Теперь s_1 == {1, 2, 3}.
s_1 |= s_2
print('s_1 |= s_2 ->', s_1)		
# Теперь s_1 == set().
s_1 -= s_2
print('s_1 -= s_2 ->', s_1)		
# Теперь s_1 == {2, 1, 3}.
s_1 ^= s_2
print('s_1 ^= s_2 ->', s_1)
s_1 < s_2 -> True
s_1 > s_2 -> False

s_1 & s_2 -> {1, 2}
s_1 | s_2 -> {1, 2, 3}
s_1 - s_2 -> set()
s_1 ^ s_2 -> {3}

s_1 &= s_2 -> {1, 2}
s_1 |= s_2 -> {1, 2, 3}
s_1 -= s_2 -> set()
s_1 ^= s_2 -> {2, 1, 3}




















		
			

Пример №4. Математические операции над множествами.

Следует помнить, что известные нам математические операторы >, >=, < и <= не сравнивают множества по количеству элементов, а проверяют на вхождение одного множества в другое (поэтому, например, операция {1, 2, 3} > {4, 5} вернет False, хотя элементов в первом множестве больше).

Что касается оператора проверки на вхождение in, то примени­тельно к мно­жествам он совершает поиск переданного объекта (левый операнд) среди элементов целевого множества (правый операнд). В случае успеха операция возвращает True, иначе – False (см. пример №5).

Код Результат pythonCodes
# Сохраняем множество в переменной.
s_1 = {1, 2, 3}
				
# Вернет True.
print('2 in s_1 ->', 2 in s_1, end='\n\n')
# Вернет False.
print("'2' in s_1 ->", '2' in s_1, end='\n\n')		
# Вернет True.
print("'2' not in s_1 ->", '2' not in s_1)
2 in s_1 -> True

'2' in s_1 -> False

'2' not in s_1 -> True


		
			

Пример №5. Использование оператора in применительно к множествам.

Применим к множествам и оператор цикла for, который обходит множество по его элементам (см. пример №6).

Код Результат pythonCodes
# Сохраняем множество в переменной.
s_1 = {1, 2, 0.3}
				
# Запускаем цикл по значениям мн-ва.
for val in s_1:
	
    # Если эл-т не является целым числом,
    if not isinstance(val, int):
        # выводим на экран сообщение 
        print('Не все эл-ты мн-ва целые числа.')			
        # и прерываем цикл.
        break

# Eсли цикл завершился успешно,
else:
    # выводим положительный результат. 
    print('Все эл-ты мн-ва - целые числа.')
Не все эл-ты мн-ва целые числа.














		
			

Пример №6. Использование цикла for для обхода элементов множества.

Функции и методы множеств в Python

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

Начнем с методов, которые во многом дублируют действия соответствующих математических операторов, перечисленных выше.

  • set.isdisjoint(other) – возвращает True, если у множества set нет общих элементов с указанным множеством other (см. пример №7).
  • set.issubset(other) – тоже самое, что и set <= other (см. операторы выше).
  • set.issuperset(other) – тоже самое, что и set >= other.
  • set.union(*others) – тоже самое, что и set | other | ....
  • set.intersection(*others) – тоже самое, что и set & other & ....
  • set.difference(*others) – тоже самое, что и set - other - ....
  • set.symmetric_difference(other) – тоже самое, что и set ^ other.
Код Результат pythonCodes
# Сохраняем множества в переменных.
s_1 = {1, 2}
s_2 = {2, 3}
s_3 = {3, 4}
			
# Вернет False.
res = s_1.issubset(s_2)
print('s_1.issubset(s_2) ->', res)		
# Вернет False.
res = s_1.isdisjoint(s_2)
print('s_1.isdisjoint(s_2) ->', res)
# Вернет True.
res = s_1.isdisjoint(s_3)
print('s_1.isdisjoint(s_3) ->', res, end='\n\n')		

# Получаем новые мн-ва, исх. не изменяются.

# Объединение: {1, 2, 3, 4}.
res = set.union(s_1, s_2, s_3)
print('set.union(s_1, s_2, s_3) ->', res)		
# Пересечение: set(), т.е. пустое мн-во.
res = s_1.intersection(s_2, s_3)
print('s_1.intersection(s_2, s_3) ->', res)		
# Разность: {1}.
res = set.difference(s_1, s_2, s_3)
print('set.difference(s_1, s_2, s_3) ->', res)		
# Сим. разность: {1, 3}.
res = s_1.symmetric_difference(s_2)
print('s_1.symmetric_difference(s_2) ->', res)
s_1.issubset(s_2) -> False
s_1.isdisjoint(s_2) -> False
s_1.isdisjoint(s_3) -> True

set.union(s_1, s_2, s_3) -> {1, 2, 3, 4}
s_1.intersection(s_2, s_3) -> set()
set.difference(s_1, s_2, s_3) -> {1}
s_1.symmetric_difference(s_2) -> {1, 3}















	
	
	
		
	
			

Пример №7. Методы множеств (часть 1).

Обратите внимание, что вышеперечисленные методы исходные множества не изменяют. Кроме того, как видно из примера, многие методы можно использовать как в форме общего метода класса, так и в форме метода конкретного объекта. Например, инструкции set.union(s_1, s_2, s_3) и s_1.union(s_2, s_3) в обоих случаях вернут множество {1, 2, 3, 4}.

А вот update-методы должны использоваться в форме метода конкретного объекта. Они обновляют само множество и возвращают None (см. пример №8).

  • set.update(*others) – тоже самое, что и set |= other | ....
  • set.intersection_update(*others) – тоже самое, что и set &= other & ....
  • set.difference_update(*others) – тоже самое, что и set -= other | ....
  • set.symmetric_difference_update(other) – тоже самое, что и set ^= other.
Код Результат pythonCodes
# Сохраняем множества в переменных.
s_1 = {1, 2}
s_2 = {2, 3}
s_3 = {3, 4}
			
# Здесь изменяется мн-во s_1.		
		
# Теперь s_1 == {1, 2, 3, 4}.
s_1.update(s_2, s_3)
print('s_1.union(s_2, s_3) ->', s_1)		
# Теперь s_1 == {3}.
s_1.intersection_update(s_2, s_3)
print('s_1.intersection_update(s_2, s_3) ->', s_1)		
# Теперь s_1 == set().
s_1.difference_update(s_2, s_3)
print('s_1.difference(s_2, s_3) ->', s_1)		
# Теперь s_1 == {2, 3}.
s_1.symmetric_difference_update(s_2)
print('s_1.symmetric_difference_update(s_2) ->', s_1)
s_1.union(s_2, s_3) -> {1, 2, 3, 4}
s_1.intersection_update(s_2, s_3) -> {3}
s_1.difference(s_2, s_3) -> set()
s_1.symmetric_difference_update(s_2) -> {2, 3}









	
	
	
		
	
			

Пример №8. Методы множеств (часть 2).

  • set.add(elem) – добавляет в множество указанный элемент elem и возвращает None (см. пример №9).
  • set.discard(elem) – удаляет указанный элемент elem, если он присутствует в множестве, и возвращает None.
  • set.remove(elem) – также удаляет указанный элемент elem, если он присутствует в множестве и возвращает None. Однако, в отличие от метода выше, если множество такого элемента не содержит, метод возбудит исключение KeyError.
  • set.pop() – удаляет и возвращает произвольный элемент множества. Если множество окажется пустым, метод возбудит исключение KeyError.
  • set.copy() – возвращает поверхностную копию множества.
  • set.clear() – очищает множество, удаляя все его элементы, и возвращает None.
Код Результат pythonCodes
# Сохраняем множество в переменной.
s_1 = {1, 2, 3}
					
# Теперь s_1 == {1, 2, 3, 4}.
s_1.add(4)
print('s_1.add(4) ->', s_1)		
# Теперь s_1 == {1, 2, 4}.
s_1.discard(3)
print('s_1.discard(3) ->', s_1)		
# Теперь s_1 == {1, 4}.
s_1.remove(2)
print('s_1.remove(2) ->', s_1)	
# У меня s_1 == {4}.
s_1.pop()
print('s_1.pop() ->', s_1, end='\n\n')			

# s_1 == s_2 == {4}.
s_2 = s_1.copy()
print('s_1.copy() ->', s_2)		
# Теперь s_2 == set().
s_2.clear()
print('s_2.clear() ->', s_2)			
# Выкинет 5 (KeyError).
s_1.remove(5)
s_1.add(4) -> {1, 2, 3, 4}
s_1.discard(3) -> {1, 2, 4}
s_1.remove(2) -> {1, 4}
s_1.pop() -> {4}

s_1.copy() -> {4}
s_2.clear() -> set()
5










	
	
	
		
	
			

Пример №9. Методы множеств (часть 3).

Помимо собственных методов к множествам применим и ряд встроенных функций: min() (возвращает элемент с минимальным значением, при этом элементы должны быть одного типа с возможностью сравнения), max() (возвращает элемент с максимальным значением, при этом элементы должны быть одного типа с возможностью сравнения), sum() (возвращает сумму элементов множества, при этом элементы должны быть числами), len() (возвращает количество элементов в множестве) и т.д.

Фиксированные множества в Python

Довольно часто возникают ситуации, когда нужно обеспечить неизменяемость используемого множества. В таких случаях при создании или преобразовании множества необходимо вместо конструктора set([iterable]) использовать конструктор frozenset([iterable]), который создает фиксированное множество. Единственное отличие фиксированного множества от обычного заключается в том, что оно неизменяемо. Соответственно, как и в ситуации с кортежами и списками, для фиксированных множеств становятся недоступны ряд методов, которые пытаются их изменить (см. пример №10).

Код Результат pythonCodes
# Фиксируем множество.
s_1 = frozenset({1, 2, 3})		

# Выведет 3.
print('len(s_1) ->', len(s_1))		
# 'frozenset' object has no attribute 'remove'
s_1.remove(2)
len(s_1) -> 3
'frozenset' object has no attribute 'remove'
	
	
		
	
			

Пример №10. Использование фиксированных множеств.

Краткие итоги параграфа

  • В Python множества представляют собой неупорядоченные изме­няемые коллек­ции объектов неизменяемого типа.
  • Чтобы создать литерал множества, нужно просто перечислить элементы множества через запятую внутри фигурных скобок (например, s = {'a', 'b', 'c'}). В случае необходимости последний элемент множества можно также завершить запятой. Это никак не повлияет на количество элементов множества, а значит и его длину. При этом следует помнить, что пустое множество при помощи фигурных скобок создать не получится, т.к. конструкция {} зарезервирована под пустой словарь.
  • Также множества могут быть созданы при помощи конструктора типа set([iterable]), который в качестве аргумента может принимать итерируемый объект, например, строку или список. Если использовать конструктор без аргумента, он вернет пустое множество set(). Если использовать конструктор с аргументом, он вернет множество с элементами переданного итерируемого объекта. Например, инструкция set('abc') вернет множество {'a', 'b', 'c'}.
  • Опять же, для создания множеств в Python могут использоваться генераторы множеств, которые применяют выражение к каждому элементу передаваемого итерируемого объекта и на основе их вычисления возвращают новое множество. Например, генератор {x: for x in 'abc'} вернет нам все то же множество {'a', 'b', 'c'}.
  • Что касается операторов +, +=, * и *=, то они с множествами напрямую не используются. Однако к множествам применимы оператор in и цикл for. Первый проверяет наличие в множестве целевого объекта, а второй позволяет совершить обход всех элементов множества.
  • Кроме того, множествам доступен целый ряд других математических операторов, которые позволяют выполнять над множествами операции объединения (например, {1, 2} | {2, 3}), пересечения (например, {1, 2} & {2, 3}), разности (например, {1, 2} - {2, 3}) и ряд других операций.
  • Далее мы познакомились с рядом методов типа set, которые дают нам возможность выполнять широкий спектр операций над множествами. При этом не стоит забывать, что множества изменяемы, поэтому их методы в основном изменяют множество непосредственно, а не возвращают его измененную копию. Обязательно посетите подраздел «Set Types – set, frozenset» раздела «Built-in types» стандартной библиотеки.
  • В конце параграфа мы познакомились с фиксированными множествами frozenset, которые отличаются от обычных множеств тем, что их нельзя изменять. Как и в случае с кортежами, неизменяемость фиксированных множеств приводит к тому, что многие методы, изменяющие множества непосредственно, становятся для них недоступны.

Вопросы и задания для самоконтроля

1. Какие из утверждений о множествах верны: упорядоченные коллекции, коллекции уникальных объектов, неупорядоченные последовательности, изменяемые коллекции неизменяемых объектов? Показать решение.

Ответ. Множества относятся к изменяемым неупорядоченным коллекциям уникальных и неизменяемых объектов. Поэтому верны утверждения: коллекции уникальных объектов, изменяемые коллекции неизменяемых объектов. К последовательностям множества не относятся.

2. Можно ли удалять элементы из множества или добавлять в него новые? Почему? Показать решение.

Ответ. Опять же, множества относятся к изменяемым неупорядоченным коллекциям уникальных и неизменяемых объектов. Поэтому при помощи соответствующих инструментов мы можем непосредственно изменять их, добавлять новые или удалять уже имеющиеся элементы. Главное, чтобы элементы были уникальными и неизменяемыми. Добавить, например, список в качестве элемента множества не получится. А при добавлении одинаковых элементов множество пополнится только одним из них.

3. Какие из представленых литералов относятся к типу set: {1: 'один', 2: 'два'}, {3, 4}, [3, 4], "{5, 6}"? Проверьте типы программно. Показать решение.

Ответ. Тип set: {3, 4}.

Решение Результат pythonCodes
# Выводим типы представленных литералов.
print("Тип {1: 'один', 2: 'два'}:", type({1: 'один', 2: 'два'}))
print("Тип {3, 4}:", type({3, 4}))
print("Тип [3, 4]:", type([3, 4]))
print('Тип "{3, 4}":', type("{3, 4}"))
Тип {1: 'один', 2: 'два'}: <class 'dict'>
Тип {3, 4}: <class 'set'>
Тип [3, 4]: <class 'list'>
Тип "{3, 4}": <class 'str'>
			

4. Какими будут результаты выполнения инструкций st = set(); st.add(1); print(st) и st = set(); st.add([1, 2, 3]); print(st). Объясните ответ. Показать решение.

Ответ. Первая инструкция выведет множество с одним элементом {1}. А вот во втором случае мы получим ошибку, т.к. добавлять в множество изменяемые элементы нельзя.

Решение Результат pythonCodes
# Выведет {1}.
st = set(); st.add(1); print(st)
# unhashable type: list
st = set(); st.add([1, 2, 3]); print(st)
{1}
unhashable type: 'list'

			

5. Даны два множества {1, 2, 3} и {2, 3, 4}. Какое из множеств {3, 4} и {1, 2} является их пересечением, а какое разностью первого и второго множеств? Показать решение.

Ответ. {3, 4} – результат пересечения, {1, 2} – результат разности.

Решение Результат pythonCodes
# Сохраняем множества в переменных.
s_1 = {1, 2, 3, 4}
s_2 = {3, 4, 5}
    
# Разность: {1, 2}.
print('s_1 - s_2 ->', s_1 - s_2)		
# Пересечение: {3, 4}.
print('s_1 & s_2 ->', s_1 & s_2)
s_1 - s_2 -> {1, 2}
s_1 & s_2 -> {3, 4}





			

6. Исправьте в коде пять ошибок. Показать решение.

Условие pythonCodes
# Сохраним множество в переменной.
s = [1, 2, 3, 4]		

# Добавляем в множество новый эл-т.
s.apend(5)		
# Удаляем из множества 3.
s.remuve('3')
# Очищаем множество.
clear(s) 
Условие Решение pythonCodes
# Сохраним множество в переменной.
s = [1, 2, 3, 4]		

# Добавляем в множество новый эл-т.
s.apend(5)		
# Удаляем из множества 3.
s.remuve('3')
# Очищаем множество.
clear(s)
# [1, 2, 3, 4].
s = {1, 2, 3, 4}		

# s.apend(5).
s.add(5)		
# s.remuve('3').
s.remove(3)
# clear(s).
s.clear()

7. Дополнительные тесты по теме расположены в разделе «Множества» нашего сборника тестов.

8. Дополнительные упражнения и задачи по теме расположены в разделе «Множества» нашего сборника задач и упражнений.

Быстрый переход к другим страницам