Множества
Вернёмся к прилавку. Рядом с табличкой цен висит вторая, «в наличии»: на ней только названия, без цен. Каждое название написано один раз, потому что писать pear дважды незачем.
Так устроено множество: оно хранит каждое значение один раз. Например, в списке тегов одно и то же слово может повторяться, а нужны только разные теги. Функция set строит множество из списка и отбрасывает повторы:
tags = ["python", "web", "python", "api", "web"]
unique_tags = set(tags)
print(len(tags), len(unique_tags)) # 5 3
print(sorted(unique_tags)) # ['api', 'python', 'web']
print("api" in unique_tags) # TrueДавайте разберём по строкам:
set(tags)убирает повторы: из пяти тегов остаются три разных.print(len(tags), len(unique_tags))печатает5 3.sorted(unique_tags)возвращает список по алфавиту, так множество печатают в предсказуемом порядке."api" in unique_tagsпроверяет, есть ли элемент, и даётTrue.
Без порядка и без индексов
Литерал множества перечисляет элементы в фигурных скобках: {1, 2, 3}. Порядка у элементов нет: print может показать их в любом порядке, поэтому для вывода множество оборачивают в sorted. Индексов и срезов тоже нет: unique_tags[0] вызывает TypeError: 'set' object is not subscriptable.
Здесь табличка «в наличии» перестаёт быть точной картинкой. Строки на ней идут сверху вниз, а у множества нет ни первого элемента, ни последнего.
Поэтому set(tags) убирает повторы, но порядок списка не сохраняет. Множество подходит, когда порядок не важен: например, чтобы узнать, сколько разных тегов в списке.
Методы add и remove
Метод add добавляет элемент, а повтор ничего не меняет. Метод remove удаляет элемент:
team = {"ann", "bob"}
team.add("eve")
team.add("ann")
team.remove("bob")
print(sorted(team)) # ['ann', 'eve']Разберём по строкам:
team.add("eve")добавляет нового игрока.team.add("ann")ничего не меняет:"ann"уже в множестве.team.remove("bob")удаляет"bob", и остаются['ann', 'eve'].
Если элемента нет, remove останавливает программу ошибкой KeyError, как чтение отсутствующего ключа словаря.
Хешируемые элементы
Множество устроено как ключи словаря без значений. Отсюда два следствия:
- элементы должны быть хешируемыми, поэтому список в множество не положить:
{[1, 2]}вызываетTypeError: unhashable type: 'list'; - как и словарь, множество находит элемент по хешу, без перебора, поэтому
inздесь намного быстрее, чем в длинном списке.
Неизменяемый вариант множества — тип frozenset. Он хешируемый, поэтому годится как ключ словаря или элемент другого множества.
Этот вопрос часто задают на собеседовании: «Чем set отличается от frozenset?» Ответ: set можно менять через add и remove, а frozenset после создания не меняется. Зато frozenset хешируемый, а set — нет.
Операции
Два множества можно сравнить тремя операторами. Каждая операция возвращает новое множество, а исходные не меняются:
team_a = {"ann", "bob", "eve"}
team_b = {"bob", "kim"}
print(sorted(team_a | team_b)) # ['ann', 'bob', 'eve', 'kim']
print(sorted(team_a & team_b)) # ['bob']
print(sorted(team_a - team_b)) # ['ann', 'eve']
print(sorted(team_b - team_a)) # ['kim']Объединение |
Оператор | даёт объединение — все элементы обоих множеств, каждый по одному разу. "bob" играет в обеих командах, но в team_a | team_b он встречается один раз.
Пересечение &
Оператор & даёт пересечение — общие элементы. Здесь team_a & team_b — игроки обеих команд, то есть только "bob".
Разность -
Оператор - даёт разность — элементы первого множества, которых нет во втором. team_a - team_b — те, кто играет только в первой команде.
Разность зависит от порядка операндов: team_b - team_a даёт ['kim']. Объединение и пересечение от порядка не зависят.
Частая ошибка
Пустое множество записали как {}:
seen = {}
seen.add("ann") # ✗AttributeError: 'dict' object has no attribute 'add'Пустые фигурные скобки создают словарь, а у словаря нет метода add. Пустое множество создаётся только вызовом set().
Главное
- Множество хранит каждое значение один раз, и
set(список)убирает повторы. - У множества нет порядка и индексов, поэтому для вывода его оборачивают в
sorted. - Элементы множества должны быть хешируемыми, а
frozenset— неизменяемое и хешируемое множество. |,&и-дают объединение, пересечение и разность; пустое множество создаёт толькоset().
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.