Урок курса
Множество: создание и проверка принадлежности
Python для новичковВ прошлых уроках мы разобрали списки и словари. Список хранит элементы в порядке и допускает дубликаты, а словарь хранит пары ключ–значение. Сегодня познакомимся с новой коллекцией — множеством. Оно решает конкретную задачу: хранить только уникальные значения, не заботясь о порядке.
Что такое множество и зачем оно нужно
Представь, что ты собираешь список городов, которые посетили пользователи. Один и тот же пользователь может прислать «Москва» трижды. Если хранить города в обычном списке, дубликаты накапливаются. Множество решает это автоматически: оно просто не даёт одному и тому же значению попасть внутрь дважды.
Множество (тип set) — это встроенная коллекция Python, которая хранит только уникальные элементы. Два ключевых свойства отличают его от списка:
- Нет дубликатов. Если добавить одно и то же значение несколько раз, в множестве оно будет ровно один раз.
- Нет порядка. Множество не запоминает, в каком порядке добавлялись элементы. Поэтому к элементам нельзя обратиться по индексу — конструкция
s[0]вызовет ошибку.
Сравни со списком:
cities_list = ["Москва", "Питер", "Москва", "Казань", "Питер"]
print(cities_list) # ['Москва', 'Питер', 'Москва', 'Казань', 'Питер']
print(len(cities_list)) # 5 — все пять, включая дубли
Тот же набор данных, но через множество:
cities_set = {"Москва", "Питер", "Москва", "Казань", "Питер"}
print(cities_set) # {'Москва', 'Питер', 'Казань'} — порядок произвольный
print(len(cities_set)) # 3 — только уникальные
Порядок вывода может меняться от запуска к запуску — это нормально. Множество не обязано выдавать элементы в том же порядке, в котором они были переданы.
Когда множество уместно, а когда нет:
- Нужно хранить уникальные значения и быстро проверять, есть ли что-то в коллекции — множество подходит.
- Нужно хранить порядок, дубликаты или обращаться к элементам по позиции — нужен список.
Свойство уникальности — не просто техническая деталь, а главная причина, зачем вообще использовать set. Всё остальное в уроке строится вокруг этой идеи.
Создание множества: литерал, конструктор и ловушка с {}
Создать множество можно двумя способами, и у каждого своя область применения.
Литерал — когда элементы уже известны заранее. Просто перечисляешь значения через запятую в фигурных скобках:
genres = {"рок", "джаз", "поп"}
print(genres) # {'рок', 'джаз', 'поп'} — порядок может отличаться
print(type(genres)) # <class 'set'>
Конструктор set() — когда нужно создать пустое множество или преобразовать уже существующую последовательность:
empty = set() # пустое множество
print(empty) # set()
print(type(empty)) # <class 'set'>
tags = set(["python", "data", "python", "code"]) # из списка с дублями
print(tags) # {'python', 'data', 'code'}
Во втором примере set() принял список как аргумент и убрал повтор "python" автоматически.
Ловушка с пустыми {}
Есть момент, на котором спотыкаются почти все, кто знакомится с множеством после словарей. Пустые фигурные скобки {} в Python — это словарь, а не множество:
wrong = {}
print(type(wrong)) # <class 'dict'> — словарь!
correct = set()
print(type(correct)) # <class 'set'> — то что нужно
Если написать s = {} и потом попробовать вызвать s.add("что-то"), Python выдаст AttributeError — у словаря нет метода add(). Ошибка не всегда очевидна, потому что на вид {} выглядит как разумная запись.
Правило простое: пустое множество — только через set(). Литерал {...} работает только тогда, когда внутри есть хотя бы один элемент.
Изменение множества: add(), discard() и безопасное удаление
Множество не статично: после создания в него можно добавлять и удалять элементы. Для этого есть два метода — add() и discard().
add() добавляет элемент в множество. Если элемент уже есть, ничего не происходит — никакой ошибки, множество просто остаётся прежним:
visited = {"Москва", "Казань"}
visited.add("Питер")
print(visited) # {'Москва', 'Казань', 'Питер'}
visited.add("Москва") # уже есть
print(visited) # {'Москва', 'Казань', 'Питер'} — без изменений
Вот здесь уникальность работает на практике: add() не создаёт дубликат, даже если вызвать его несколько раз с одним и тем же значением.
discard() удаляет элемент из множества. Ключевое слово — «безопасно»: если элемента нет, метод молча ничего не делает:
visited.discard("Казань")
print(visited) # {'Москва', 'Питер'}
visited.discard("Новосибирск") # такого нет в множестве
print(visited) # {'Москва', 'Питер'} — никакой ошибки
Такое поведение принципиально отличает discard() от remove(). Метод remove() есть и у множества, и у списка — но при попытке удалить несуществующий элемент он бросает исключение:
visited.remove("Новосибирск") # KeyError: 'Новосибирск'
Это не значит, что remove() плохой — просто у него другая задача. Если хочешь гарантированно получить ошибку при отсутствии элемента (например, чтобы отловить логический баг), используй remove(). Если хочешь просто «убрать, если есть» — используй discard().
Аналогия со списком помогает быстро запомнить разницу: append() добавляет в конец списка, add() добавляет в множество. remove() у списка тоже падает с ошибкой при отсутствии элемента — discard() это исправляет специально для множеств.
Практический сценарий: пользователи отмечают города, которые хотят посетить. Список пожеланий собирается динамически — элементы приходят один за другим, некоторые повторяются, а некоторые потом отзываются:
wishlist = set()
wishlist.add("Берлин")
wishlist.add("Токио")
wishlist.add("Берлин") # повтор — игнорируется
wishlist.discard("Токио") # передумал
wishlist.discard("Рим") # не было — не падает
print(wishlist) # {'Берлин'}
Весь блок работает без ошибок, даже если данные приходят непоследовательно. Именно за это и ценят discard() в сценариях, где наличие элемента заранее неизвестно.
Проверка принадлежности оператором in и получение уникальных элементов из списка
Два самых частых сценария работы с множеством — проверить, есть ли что-то внутри, и убрать дубликаты из списка. Оба делаются в одну строку.
Оператор in
Для множества in работает так же, как для списка: возвращает True или False. Синтаксис одинаковый, но есть практическое преимущество: множество устроено иначе внутри — детали этого изучают позже, но на практике это означает значительно более быструю проверку, чем у списка, даже при большом числе элементов.
Пример с городами:
visited = {"Москва", "Питер", "Казань"}
print("Москва" in visited) # True
print("Новосибирск" in visited) # False
print("Питер" not in visited) # False
Это удобно в условиях. Например, чтобы не добавлять пользователя в рассылку дважды:
subscribed = {"alice@mail.ru", "bob@mail.ru"}
user = "carol@mail.ru"
if user not in subscribed:
subscribed.add(user)
print(f"{user} добавлен в рассылку")
else:
print(f"{user} уже подписан")
Здесь in и add() работают вместе: проверяем членство — добавляем только тех, кого ещё нет.
Паттерн set(список) для дедупликации
Если есть список с повторами и нужны только уникальные значения — конвертируй его в множество:
cities = ["Москва", "Питер", "Москва", "Казань", "Питер", "Казань"]
unique_cities = set(cities)
print(unique_cities) # {'Москва', 'Питер', 'Казань'} — порядок произвольный
Если после дедупликации нужен список (например, чтобы отсортировать или передать в функцию, которая ждёт именно список):
unique_sorted = sorted(set(cities))
print(unique_sorted) # ['Казань', 'Москва', 'Питер']
sorted() принимает любую коллекцию, поэтому его можно применить прямо к множеству — результат будет списком, отсортированным по алфавиту.
Полный мини-сценарий: собираем теги из нескольких источников, убираем дубликаты и проверяем, есть ли нужный тег:
raw_tags = ["python", "data", "python", "ml", "data", "python"]
tags = set(raw_tags)
print(tags) # {'python', 'data', 'ml'}
print("ml" in tags) # True
print("deep" in tags) # False
Один вызов set() — и список из шести элементов превращается в три уникальных. После этого in позволяет быстро проверить наличие любого тега.
Задача 1
Программист написал:
s = {}
print(type(s))
Какой тип выведет Python?
Задача 2
Что выведет следующий код? Напишите одно число.
nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3}
print(len(nums))
Задача 3
Посмотрите на код:
tags = {'python', 'код', 'урок'}
print('код' in tags)
print('java' in tags)
Что выведет программа?
Задача 4
Программист хочет вывести количество уникальных товаров из списка с дубликатами:
shop = ['хлеб', 'молоко', 'хлеб', 'сыр']
Какой код решает задачу правильно?
Задача 5
Посмотрите на код:
visited = {'Москва', 'Берлин', 'Париж'}
visited.discard('Берлин')
visited.discard('Токио')
print(len(visited))
Что выведет программа?
Задача 6
Интересы участников
В начале программы в файле уже должно быть создано пустое множество interests = set().
Затем добавьте в него по очереди темы python, math, python.
После этого программа читает одну строку из ввода — тему участника.
Если эта тема уже есть в множестве, выведите Да, иначе — Нет.
Повторное добавление одинаковой темы не должно увеличивать число элементов в множестве.
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Задача 7
Безопасно удали два имени
В программе уже задано множество subscribers = {'anna', 'boris', 'vika'}.
Прочитайте две строки — два имени, которые нужно удалить. Удалите каждое имя из множества методом discard().
Выведите результат строго в двух строках:
- в первой строке — количество оставшихся подписчиков;
- во второй строке — оставшиеся имена в алфавитном порядке, разделённые одним пробелом.
Выводите имена без фигурных скобок, кавычек и запятых. Чтобы получить стабильный порядок, используйте sorted(subscribers).
Если какого-либо имени в множестве нет, программа всё равно должна завершиться без ошибки.
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Задача 8
Проверь повторяющиеся слова в строке
Программа получает одну строку с названиями слов через пробел.
Нужно:
- превратить ввод в список слов;
- получить из него множество уникальных слов;
- вывести сначала количество уникальных слов;
- затем вывести:
Есть повторения, если в исходной строке были одинаковые слова;Повторов нет, если все слова были разными.
Повторения определяйте только сравнением количества слов до и после преобразования в множество.
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Задачи к уроку
- Python set.discard: удаление элементов без KeyError
Удалите два имени из множества методом discard и проверьте результат. Короткая практическая задача по Python.
- Множество Python: найти повторяющиеся слова в строке
Используйте set, чтобы проверить повторения слов в тексте. Практическая задача на множества Python с онлайн-проверкой.
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
