← Назад к вопросам

Какие структуры данных можно добавлять в множество (Set) в Python?

1.3 Junior🔥 91 комментариев
#Python и программирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Структуры данных в Python Set

Mножество (Set) в Python — это неупорядоченная коллекция уникальных элементов. Однако есть важные ограничения на то, что можно добавлять в Set. Это критично понимать для корректной работы с данными.

1. Какие типы МОЖНО добавлять в Set

В Set могут добавляться только хешируемые (hashable) типы данных — те, которые имеют неизменяемое значение хеша.

Базовые типы

# Целые числа
numbers_set = {1, 2, 3, 4, 5}
print(numbers_set)  # {1, 2, 3, 4, 5}

# Вещественные числа
floats_set = {1.5, 2.3, 3.14}
print(floats_set)  # {1.5, 2.3, 3.14}

# Строки (НЕИЗМЕНЯЕМЫЕ)
names_set = {'Alice', 'Bob', 'Charlie'}
print(names_set)  # {'Alice', 'Bob', 'Charlie'}

# Булевы значения
bool_set = {True, False}
print(bool_set)  # {True, False}

# None
special_set = {1, 'string', None, 3.14}
print(special_set)  # {1, 'string', None, 3.14}

Кортежи (Tuples) — МОЖНО, если содержат хешируемые элементы

# Кортежи с примитивными типами
tuples_set = {(1, 2), (3, 4), (5, 6)}
print(tuples_set)  # {(1, 2), (3, 4), (5, 6)}

# Смешанные кортежи
mixed_tuples = {(1, 'Alice'), (2, 'Bob'), (3, 'Charlie')}
print(mixed_tuples)  # {(1, 'Alice'), (2, 'Bob'), (3, 'Charlie')}

# Вложенные кортежи
nested_tuples = {(1, (2, 3)), (4, (5, 6))}
print(nested_tuples)  # {(1, (2, 3)), (4, (5, 6))}

# Но если кортеж содержит список — ОШИБКА
try:
    bad_set = {(1, [2, 3])}  # ERROR!
except TypeError as e:
    print(f"Ошибка: {e}")  # unhashable type: 'list'

Диапазоны (range)

# Нельзя напрямую добавлять range, но можно кортеж из range
range_set = {1, 2, 3, 4, 5}  # хотя это одно и то же

# На практике для диапазонов используют list/tuple
range_tuple = tuple(range(5))
range_set_from_tuple = {range_tuple}
print(range_set_from_tuple)  # {(0, 1, 2, 3, 4)}

frozenset — НЕИЗМЕНЯЕМОЕ множество

# frozenset — это хешируемое множество
fs1 = frozenset({1, 2, 3})
fs2 = frozenset({3, 4, 5})

# Можно добавлять frozenset в Set
set_of_sets = {fs1, fs2}
print(set_of_sets)  # {frozenset({1, 2, 3}), frozenset({3, 4, 5})}

# Операции с frozenset
intersection = fs1 & fs2  # {3}
union = fs1 | fs2  # {1, 2, 3, 4, 5}
difference = fs1 - fs2  # {1, 2}

2. Какие типы НЕЛЬЗЯ добавлять в Set

Список (List) — НЕЛЬЗЯ

try:
    bad_set = {[1, 2, 3]}  # ERROR!
except TypeError as e:
    print(f"Ошибка: {e}")  # unhashable type: 'list'

# Причина: списки мутабельны (изменяемы)
my_list = [1, 2, 3]
my_list[0] = 999  # можно изменить
# Если список в Set, то хеш изменится — нарушится целостность Set

Словарь (Dict) — НЕЛЬЗЯ

try:
    bad_set = {{'key': 'value'}}  # ERROR!
except TypeError as e:
    print(f"Ошибка: {e}")  # unhashable type: 'dict'

# Словари мутабельны
my_dict = {'a': 1}
my_dict['b'] = 2  # можно добавить ключ

Множество (Set) — НЕЛЬЗЯ

try:
    bad_set = {{1, 2, 3}}  # ERROR!
except TypeError as e:
    print(f"Ошибка: {e}")  # unhashable type: 'set'

# Множества мутабельны
my_set = {1, 2, 3}
my_set.add(4)  # можно добавлять элементы

Кортежи, содержащие мутабельные типы — НЕЛЬЗЯ

try:
    # Кортеж с списком внутри
    bad_set = {(1, [2, 3])}  # ERROR!
except TypeError as e:
    print(f"Ошибка: {e}")  # unhashable type: 'list'

try:
    # Кортеж со словарем
    bad_set = {(1, {'a': 2})}  # ERROR!
except TypeError as e:
    print(f"Ошибка: {e}")  # unhashable type: 'dict'

try:
    # Кортеж с множеством
    bad_set = {(1, {2, 3})}  # ERROR!
except TypeError as e:
    print(f"Ошибка: {e}")  # unhashable type: 'set'

3. Проверка хешируемости

# Функция для проверки хешируемости
def is_hashable(obj):
    try:
        hash(obj)
        return True
    except TypeError:
        return False

# Проверки
print(is_hashable(5))  # True
print(is_hashable('string'))  # True
print(is_hashable((1, 2, 3)))  # True
print(is_hashable([1, 2, 3]))  # False
print(is_hashable({'a': 1}))  # False
print(is_hashable({1, 2}))  # False
print(is_hashable(frozenset([1, 2])))  # True

# Хеш функция
print(hash(42))  # -9223372036854775267
print(hash('hello'))  # 2087996389530872619
print(hash((1, 2, 3)))  # -4010321260515556519

try:
    print(hash([1, 2, 3]))  # ERROR!
except TypeError as e:
    print(f"Ошибка: {e}")  # unhashable type: 'list'

4. Практические примеры использования Set

Пример 1: Удаление дубликатов

# Из списка
data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique_data = list(set(data))
print(unique_data)  # [1, 2, 3, 4]

# Из строк (почтовые адреса)
emails = ['alice@mail.com', 'bob@mail.com', 'alice@mail.com']
unique_emails = set(emails)
print(unique_emails)  # {'alice@mail.com', 'bob@mail.com'}

Пример 2: Объединение и пересечение

# Пользователи, посетившие сайт в разные дни
day1_users = {101, 102, 103, 104}
day2_users = {103, 104, 105, 106}

# Все пользователи
all_users = day1_users | day2_users
print(all_users)  # {101, 102, 103, 104, 105, 106}

# Пользователи, посетившие оба дня
both_days = day1_users & day2_users
print(both_days)  # {103, 104}

# Только в день 1
only_day1 = day1_users - day2_users
print(only_day1)  # {101, 102}

# Эксклюзивные пользователи (в одном дне, но не в обоих)
exclusive = day1_users ^ day2_users
print(exclusive)  # {101, 102, 105, 106}

Пример 3: С кортежами для координат

# Уникальные координаты пользователей
coordinates = {
    (40.7128, -74.0060),  # New York
    (51.5074, -0.1278),   # London
    (40.7128, -74.0060),  # New York (дубликат)
    (48.8566, 2.3522)     # Paris
}

print(len(coordinates))  # 3
for lat, lon in coordinates:
    print(f"Координата: ({lat}, {lon})")

Пример 4: С frozenset для групп

# Группы пользователей с одинаковыми предпочтениями
preferences1 = frozenset({'Python', 'SQL', 'Analytics'})
preferences2 = frozenset({'Python', 'JavaScript', 'Web'})
preferences3 = frozenset({'Python', 'SQL', 'Analytics'})

# Все уникальные наборы предпочтений
all_prefs = {preferences1, preferences2, preferences3}
print(len(all_prefs))  # 2 (preferences1 и preferences3 идентичны)

for pref in all_prefs:
    print(f"Группа: {', '.join(pref)}")

5. Кастомные объекты в Set

Для того чтобы добавлять кастомные объекты в Set, нужно реализовать метод __hash__ и __eq__:

class User:
    def __init__(self, user_id, name):
        self.user_id = user_id
        self.name = name
    
    def __hash__(self):
        # Хеш должен быть неизменяемым
        return hash(self.user_id)
    
    def __eq__(self, other):
        # Проверка равенства по user_id
        if not isinstance(other, User):
            return False
        return self.user_id == other.user_id
    
    def __repr__(self):
        return f"User({self.user_id}, {self.name})"

# Теперь можно добавлять User в Set
users_set = {
    User(1, 'Alice'),
    User(2, 'Bob'),
    User(1, 'Alice')  # дубликат по user_id
}

print(len(users_set))  # 2
for user in users_set:
    print(user)

Сводная таблица

ТипХешируемыйМожно в SetПример
int, float, boolДаДа{1, 2.5, True}
strДаДа{'a', 'b', 'c'}
tuple (с хешируемыми)ДаДа{(1, 2), (3, 4)}
frozensetДаДа{frozenset([1, 2])}
listНетНет{[1, 2]} ✗
dictНетНет{{'a': 1}} ✗
setНетНет{{1, 2}} ✗
tuple (с list/dict/set)НетНет{(1, [2])} ✗

Практическая рекомендация для Data Analyst

При работе с данными:

  1. Для удаления дубликатов — используйте set() с примитивными типами
  2. Для координат/пар — используйте кортежи в Set
  3. Для вложенных структур — используйте frozenset или кастомные хешируемые объекты
  4. Помните о порядке — Set не сохраняет порядок, используйте dict если порядок важен (Python 3.7+)
  5. Производительность — Set имеет O(1) для проверки наличия элемента, что быстрее, чем list с O(n)

Основной принцип: в Set можно добавлять только то, что не может меняться после добавления.

Какие структуры данных можно добавлять в множество (Set) в Python? | PrepBro