Set в Python — это множество, встроенный тип для набора уникальных значений без порядка. Создают его фигурными скобками {1, 2, 3} или функцией set(), причём повторы при создании пропадают сами: из [5, 5, 7] получится {5, 7}. Пустое множество пишут только как set(), потому что {} даёт пустой словарь.
Множествами убирают дубли, быстро проверяют, есть ли элемент в наборе, и сравнивают два набора: что общего, чего не хватает, что лишнее. Ниже каждый приём показан на коде с реальным выводом. Если вы ещё путаетесь в базовых коллекциях, сначала прочитайте, как устроены списки в Python, а про сами имена и присваивание есть отдельная статья о переменных.
Шпаргалка по множествам в одной таблице

Все примеры в таблице считаются для a = {1, 2, 3, 4} и b = {3, 4, 5, 6}.
| Что нужно | Оператор | Метод | Результат |
|---|---|---|---|
| Объединение (всё из обоих) | a | b |
a.union(b) |
{1, 2, 3, 4, 5, 6} |
| Пересечение (только общее) | a & b |
a.intersection(b) |
{3, 4} |
| Разность (есть в a, нет в b) | a - b |
a.difference(b) |
{1, 2} |
| Симметрическая разность (есть только в одном) | a ^ b |
a.symmetric_difference(b) |
{1, 2, 5, 6} |
| Подмножество | a <= b |
a.issubset(b) |
False |
| Нет общих элементов | нет | a.isdisjoint(b) |
False |
| Добавить элемент | нет | a.add(7) |
изменяет a |
| Удалить без ошибки | нет | a.discard(9) |
изменяет a, ошибки нет |
Как создать множество в Python
Способов три, и у каждого своя задача. Порядок вывода в примерах может отличаться от вашего, об этом подробно ниже, в разделе про ошибки.
Фигурные скобки
Элементы перечисляют через запятую. Повторы Python отбрасывает сразу:
numbers = {3, 1, 2, 3, 1}
print(numbers)
print(len(numbers))
print(type(numbers))
{1, 2, 3}
3
<class 'set'>
Функция set()
Функция принимает любой перебираемый объект: список, кортеж, строку, range. Со строкой будьте внимательны: set() разберёт её на отдельные символы.
from_list = set([5, 5, 7, 7, 7])
print(from_list)
letters = set("ааббв")
print(sorted(letters))
empty = set()
print(empty, type(empty))
not_a_set = {}
print(type(not_a_set))
{5, 7}
['а', 'б', 'в']
set() <class 'set'>
<class 'dict'>
Последние две строки показывают главную ловушку новичка. Пустые фигурные скобки создают словарь, а не множество, так прямо и сказано в учебнике на docs.python.org.
Генератор множества
Это та же запись, что и генератор списка, только в фигурных скобках. Удобно, когда элементы надо сразу посчитать или отфильтровать:
squares = {n * n for n in range(-3, 4)}
print(squares)
{0, 9, 4, 1}
Из семи чисел от −3 до 3 получилось четыре квадрата: 9, 4 и 1 повторялись для отрицательных и положительных чисел.
Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединитьсяЧто можно положить во множество
Элементом множества может быть только хешируемый объект, то есть такой, у которого есть постоянный хеш. На практике это числа, строки, кортежи из неизменяемых значений и frozenset. Изменяемые объекты вроде списка, словаря и обычного множества внутрь не попадут.
ok = {1, 2.5, "текст", (1, 2), True}
print(len(ok))
bad = {[1, 2], 3}
Python 3.12 выведет:
4
TypeError: unhashable type: 'list'
В Python 3.14 сообщение подробнее: TypeError: cannot use 'list' as a set element (unhashable type: 'list'). Если нужен составной элемент, превратите список в кортеж: (1, 2) вместо [1, 2]. Чем кортеж отличается от списка, мы разбирали в статье про кортежи.
Вы могли заметить, что в ok пять значений, а len() вернул 4. Дело в том, что True и 1 для Python равны и дают одинаковый хеш, поэтому во множестве остаётся только первый из них:
print({True, 1, 1.0})
print({0, False})
{True}
{0}
Как добавить и удалить элементы
У множества нет индексов, поэтому a[0] не сработает. Элементы добавляют и удаляют методами:
| Метод | Что делает | Если элемента нет |
|---|---|---|
add(x) |
добавляет один элемент | добавит; если есть, ничего не изменится |
update(…) |
добавляет все элементы из одного или нескольких наборов | то же |
remove(x) |
удаляет элемент | KeyError |
discard(x) |
удаляет элемент | молча ничего не делает |
pop() |
удаляет и возвращает произвольный элемент | KeyError на пустом множестве |
clear() |
очищает множество целиком | нет |
tags = {"python"}
tags.add("set")
tags.add("python")
print(sorted(tags))
tags.update(["list", "dict"], ("tuple",))
print(sorted(tags))
['python', 'set']
['dict', 'list', 'python', 'set', 'tuple']
Повторный add("python") ошибки не дал и ничего не добавил. А вот разница между remove() и discard() важна:
colors = {"red", "green", "blue"}
colors.discard("black")
print(sorted(colors))
colors.remove("black")
['blue', 'green', 'red']
KeyError: 'black'
Решение: если элемента может не оказаться, берите discard(). remove() оставьте для случаев, когда отсутствие элемента означает ошибку в программе и её лучше увидеть сразу. Метод pop() по документации возвращает произвольный элемент, поэтому рассчитывать на «первый» или «последний» нельзя. У списка порядок есть, поэтому и удалять из него можно по индексу: как удалить элемент из списка в Python.
Объединение, пересечение и разность множеств

Ради этих операций множества чаще всего и берут. Возьмём два набора чисел:
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b)
print(a & b)
print(a - b)
print(b - a)
print(a ^ b)
{1, 2, 3, 4, 5, 6}
{3, 4}
{1, 2}
{5, 6}
{1, 2, 5, 6}
|: объединение, все элементы из обоих множеств без повторов.&: пересечение, только то, что есть в обоих.-: разность, то, что есть в левом и нет в правом. Порядок важен:a - bиb - aдают разное.^: симметрическая разность, элементы, которые есть ровно в одном из двух.
Те же знаки у чисел означают совсем другое: | и & там побитовые операции. Таблица всех операторов есть в статье про операторы Python.
Методы или операторы
У каждой операции есть метод: union(), intersection(), difference(), symmetric_difference(). Разница одна, но заметная. Метод принимает любой перебираемый объект, а оператору нужно множество с обеих сторон:
a = {1, 2, 3}
print(a.union([3, 4], (5,)))
print(a.intersection(range(2, 10)))
print(a | [3, 4])
{1, 2, 3, 4, 5}
{2, 3}
TypeError: unsupported operand type(s) for |: 'set' and 'list'
Так задумано: в документации типа set сказано, что методы принимают любой итерируемый аргумент, а операторам нужны множества. Если данные пришли списком, вызовите метод или оберните список в set().
Изменить множество на месте
Операторы |=, &=, -= и ^= не создают новое множество, а меняют левое. Это же делают методы update(), intersection_update(), difference_update() и symmetric_difference_update().
a = {1, 2, 3, 4}
b = {3, 4, 5}
a -= b
print(a)
a |= {7}
print(a)
a &= {1, 7, 9}
print(a)
{1, 2}
{1, 2, 7}
{1, 7}
Если вы привыкли к спискам, add() работает как append(), а update() как extend(): добавляет всё из другого набора. Как эти методы ведут себя у списков, мы разбирали в статье как добавить элемент в список Python.
Как проверить элемент и сравнить два множества
Проверка in выглядит так же, как у списка:
week = {"пн", "вт", "ср"}
print("вт" in week)
print("сб" not in week)
True
True
Разница в том, как Python ищет. Список он перебирает с начала до совпадения, примерно как вы сделали бы это циклом while с проверкой каждого элемента.
Множество устроено как хеш-таблица: Python считает хеш значения и сразу смотрит в нужную ячейку. На наборе из нескольких элементов разницы не видно. А на сотнях тысяч поиск в списке растёт вместе с длиной, в множестве же в среднем занимает одинаковое время. Поэтому проверку на вхождение документация Python называет одним из основных применений множеств.
Для сравнения наборов есть пять операций:
small = {1, 2}
big = {1, 2, 3}
print(small <= big, small.issubset(big))
print(small < big)
print(big < big, big <= big)
print(big >= small, big.issuperset(small))
print(small.isdisjoint({8, 9}))
print({1, 2} == {2, 1})
True True
True
False True
True True
True
True
<=илиissubset(): все элементы левого есть в правом.<: то же, но множества не равны. Поэтомуbig < bigдаётFalse.>=илиissuperset(): левое содержит всё из правого.isdisjoint():True, если общих элементов нет вообще.==: одинаковый состав, порядок записи не важен.
frozenset: неизменяемое множество
frozenset умеет всё, что не меняет набор: операции, сравнения, in, len(). Методов add(), remove() и других изменяющих у него нет. Зато он хешируемый, и его можно сделать ключом словаря или элементом другого множества. Обычный set так не может, это прямо сказано в описании frozenset.
frozen = frozenset([1, 2, 2, 3])
print(frozen)
routes = {frozenset({"Москва", "Казань"}): 820}
print(routes[frozenset({"Казань", "Москва"})])
print(frozen | {4})
frozen.add(4)
frozenset({1, 2, 3})
820
frozenset({1, 2, 3, 4})
AttributeError: 'frozenset' object has no attribute 'add'
Пример с маршрутами показывает, зачем это нужно. Ключ frozenset({"Москва", "Казань"}) не зависит от порядка городов, поэтому значение находится по паре в любом порядке, и вторую запись «Казань — Москва» заводить не нужно. Операции вроде frozen | {4} работают, но возвращают новый объект, а исходный остаётся прежним.
Где множества пригодятся на практике

Три задачи встречаются постоянно.
Убрать дубли из списка. Если порядок не важен, хватит set(список). Если важен, используйте словарь: с Python 3.7 он гарантированно хранит порядок добавления, и dict.fromkeys() оставит первое появление каждого значения.
emails = ["a@mail.ru", "b@mail.ru", "a@mail.ru", "c@mail.ru", "b@mail.ru"]
print(len(set(emails)))
unique_in_order = list(dict.fromkeys(emails))
print(unique_in_order)
3
['a@mail.ru', 'b@mail.ru', 'c@mail.ru']
Сравнить два списка. Например, кто из пользователей появился сегодня, кто пропал и кто был оба дня:
yesterday = {"anna", "boris", "vera"}
today = {"boris", "vera", "gleb"}
print("новые:", sorted(today - yesterday))
print("ушли:", sorted(yesterday - today))
print("оба дня:", sorted(yesterday & today))
новые: ['gleb']
ушли: ['anna']
оба дня: ['boris', 'vera']
Быстро проверять «было или нет». Список уже обработанных ID, стоп-слов или посещённых страниц лучше хранить во множестве: каждая проверка in не перебирает весь набор. В базах данных ту же задачу решает DISTINCT в SQL, а потренироваться на множествах можно в задачах по Python для начинающих.
Частые ошибки с множествами
- Создали пустое множество через
{}. Получился словарь, иadd()падает сAttributeError: 'dict' object has no attribute 'add'. Решение:set(). - Положили список.
TypeError: unhashable type: 'list'. Решение: кортеж вместо списка илиfrozensetвместо вложенного множества. - Ждут порядок. Множество не помнит, в каком порядке добавляли элементы, и индексов у него нет. Если порядок нужен, сортируйте:
sorted(s)вернёт список. - Удалили несуществующий элемент через
remove(). ПолучилиKeyError. Решение:discard()или проверкаif x in s. - Меняли множество внутри цикла по нему. Python остановит программу с ошибкой
RuntimeError: Set changed size during iteration. Решение ниже.
Так делать нельзя:
nums = {1, 2, 3, 4}
for n in nums:
if n % 2 == 0:
nums.discard(n)
RuntimeError: Set changed size during iteration
Решение: соберите новое множество генератором и присвойте его той же переменной.
nums = {1, 2, 3, 4}
nums = {n for n in nums if n % 2 != 0}
print(nums)
{1, 3}
Почему порядок строк меняется от запуска к запуску
Целые числа в небольших множествах часто выводятся по возрастанию, и легко решить, что множество их сортирует. Со строками видно, что это не так. Запустите одну строку кода несколько раз:
print({"кот", "пёс", "ёж"})
{'кот', 'ёж', 'пёс'}
{'ёж', 'пёс', 'кот'}
{'пёс', 'кот', 'ёж'}
Хеши строк Python при каждом запуске «солит» случайным значением, это включено по умолчанию и защищает от атак на хеш-таблицы. Порядок элементов во множестве зависит от хешей, поэтому меняется вместе с ними. Если тест сравнивает вывод множества строкой, он будет то проходить, то падать. Сравнивайте сами множества через == или выводите sorted(), как в примерах этой статьи.
Где освоить Python системно
Множества закрывают одну задачу: работу с уникальными значениями. Дальше пойдут словари, функции и классы, а потом первые проекты, где все эти типы встречаются вместе. Продолжить можно со статьи про функции, а если хочется программы с наставником и проверкой домашних заданий, сравните курсы в каталоге курсов по Python.
| Курс | Школа | Стоимость со скидкой | В рассрочку | Длительность | Обзор курса от Checkroi |
|---|---|---|---|---|---|
| Профессия «Python-разработчик» Перейти на сайт курса | 157 335 ₽ | 5987 ₽/мес. | 10 месяцев | Обзор курса | |
| Fullstack-разработчик на Python Перейти на сайт курса | 137 000 ₽ | 7125 ₽/мес. | 21 месяц | Обзор курса | |
| ДО Профессия Python-разработчик Перейти на сайт курса | 149 001 ₽ | 3167 ₽/мес. | 10 месяцев | Обзор курса | |
| Автоматизированное тестирование на Python Перейти на сайт курса | 122 226 ₽ | 4108 ₽/мес. | 9 месяцев | Обзор курса | |
| Профессия Python-разработчик Перейти на сайт курса | 140 040 ₽ | 3890 ₽/мес. | 10 месяцев | Обзор курса |
Больше программ — в полном каталоге курсов по Python




