← Назад к вопросам
Какие структуры данных можно добавлять в множество (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
При работе с данными:
- Для удаления дубликатов — используйте
set()с примитивными типами - Для координат/пар — используйте кортежи в Set
- Для вложенных структур — используйте
frozensetили кастомные хешируемые объекты - Помните о порядке — Set не сохраняет порядок, используйте
dictесли порядок важен (Python 3.7+) - Производительность — Set имеет O(1) для проверки наличия элемента, что быстрее, чем list с O(n)
Основной принцип: в Set можно добавлять только то, что не может меняться после добавления.