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

Что может находиться в set?

2.0 Middle🔥 111 комментариев
#Python Core

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

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

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

Что может находиться в set в Python

Это важный вопрос о типах данных в Python. Правило простое: в set могут находиться только хешируемые объекты (hashable). Разберу подробно.

Основное правило

Set может содержать только объекты, у которых:

  1. Определён метод __hash__() (вычисляет хеш)
  2. Объект неизменяемый (immutable)
  3. Объект реализует __eq__() для сравнения
# ✅ Хешируемые типы (могут быть в set)
ints_set = {1, 2, 3, 4, 5}
strings_set = {"apple", "banana", "cherry"}
tuples_set = {(1, 2), (3, 4), (5, 6)}  # Кортежи хешируемы
frozensets_set = {frozenset([1, 2]), frozenset([3, 4])}
bool_set = {True, False}
none_set = {None}
mixed_set = {1, "hello", 3.14, True, None}

print(f"Целые числа: {ints_set}")
print(f"Строки: {strings_set}")
print(f"Кортежи: {tuples_set}")

# ❌ НЕХЕШИРУЕМЫЕ типы (НЕ могут быть в set)
# list_set = {[1, 2, 3]}  # TypeError: unhashable type: 'list'
# dict_set = {{"a": 1}}   # TypeError: unhashable type: 'dict'
# set_set = {{1, 2, 3}}   # TypeError: unhashable type: 'set'

Встроенные хешируемые типы

1. Числа (int, float, complex)

numbers = {1, 2.5, 3+4j, -10, 0, 1e-5}
print(f"Числа: {numbers}")

# Хеш стабилен на протяжении жизни объекта
print(f"hash(5) = {hash(5)}")
print(f"hash(3.14) = {hash(3.14)}")
print(f"hash(1+2j) = {hash(1+2j)}")

2. Строки (str)

words = {"Python", "Java", "Rust", "Go"}
print(f"Строки: {words}")

# Одинаковые строки дают одинаковый хеш
print(f"hash('hello') = {hash('hello')}")
print(f"hash('hello') = {hash('hello')}")  # Тот же хеш

# Полезно для удаления дубликатов
список = ["apple", "banana", "apple", "cherry", "banana"]
уникальные = set(список)
print(f"Уникальные: {уникальные}")

3. Кортежи (tuple) — если содержат только хешируемые элементы

# ✅ Хешируемые кортежи (содержат только хешируемые элементы)
tuples_set = {(1, 2), (3, 4), ("a", "b"), (1, "x", 3.14)}
print(f"Кортежи: {tuples_set}")

# ❌ НЕХЕШИРУЕМЫЕ кортежи (содержат списки или словари)
# bad_tuple_set = {(1, [2, 3])}  # TypeError: unhashable type: 'list'
# bad_tuple_set = {(1, {"a": 2})}  # TypeError: unhashable type: 'dict'

# Проверка
print(f"hash((1, 2, 3)) = {hash((1, 2, 3))}")  # Работает
# print(f"hash((1, [2], 3)) = {hash((1, [2], 3))}")  # TypeError

4. Frozenset (неизменяемое множество)

# frozenset хешируемый, set нет
fs1 = frozenset([1, 2, 3])
fs2 = frozenset([4, 5, 6])

# Можно использовать frozenset в set
set_of_frozensets = {fs1, fs2}
print(f"Set of frozensets: {set_of_frozensets}")

# ❌ Но нельзя использовать обычный set в set
# bad_set = {{1, 2, 3}}  # TypeError: unhashable type: 'set'

5. Bool (True, False)

bool_set = {True, False}
print(f"Booleans: {bool_set}")

# Интересный факт: True == 1, False == 0
# Но в set они разные элементы
print(hash(True), hash(1))  # hash(True) == hash(1)
weird_set = {1, True}  # Будет только {1} т.к. True == 1
print(f"Set с 1 и True: {weird_set}")  # {1}

6. None

with_none = {None, 1, 2, 3}
print(f"С None: {with_none}")
print(f"hash(None) = {hash(None)}")

7. Bytes и bytearray (только bytes хеширует)

bytes_set = {b"hello", b"world", b"python"}
print(f"Bytes: {bytes_set}")

# ❌ bytearray нехеширует (изменяемый)
# bad = {bytearray(b"test")}  # TypeError: unhashable type: 'bytearray'

Почему только хешируемые объекты?

# Set использует хеш для быстрого поиска (O(1))
# Хеш строится на основе содержимого объекта

# Если объект изменяемый, его хеш может измениться
mutable_list = [1, 2, 3]
original_hash = hash(id(mutable_list))  # Можно хешировать ID

mutable_list.append(4)  # Изменили
# Теперь хеш должен быть другим, но ID тот же
# Это нарушило бы структуру set!

# Поэтому Python не позволяет изменяемые объекты в set

Создание хешируемых пользовательских объектов

# ✅ Хешируемый класс
class Point:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y
    
    def __hash__(self):
        # Хеш основан на координатах
        return hash((self.x, self.y))
    
    def __eq__(self, other):
        if not isinstance(other, Point):
            return False
        return self.x == other.x and self.y == other.y
    
    def __repr__(self):
        return f"Point({self.x}, {self.y})"

# Теперь Point можно использовать в set
points = {Point(0, 0), Point(1, 1), Point(2, 2)}
print(f"Points: {points}")

# Проверка наличия
if Point(1, 1) in points:
    print("Точка (1, 1) найдена!")

# ❌ НЕХЕШИРУЕМЫЙ класс (если он изменяемый)
class MutablePoint:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    # Не определил __hash__
    # По умолчанию изменяемые объекты не хешируемы

# bad_points = {MutablePoint(0, 0)}  # TypeError: unhashable type: 'MutablePoint'

Dataclass как хешируемый объект

from dataclasses import dataclass

# ✅ Хешируемый dataclass
@dataclass(frozen=True)  # frozen=True делает его неизменяемым
class Product:
    id: int
    name: str
    price: float

products = {Product(1, "Apple", 1.5), Product(2, "Banana", 0.8)}
print(f"Товары: {products}")

# ❌ Нехешируемый dataclass (по умолчанию изменяемый)
@dataclass
class MutableProduct:
    id: int
    name: str
    price: float

# bad = {MutableProduct(1, "Apple", 1.5)}  # TypeError: unhashable type

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

1. Удаление дубликатов

data = [1, 2, 2, 3, 3, 3, 4, 5, 5]
unique = list(set(data))
print(f"Уникальные элементы: {unique}")  # [1, 2, 3, 4, 5]

2. Проверка на уникальность

def has_duplicates(items):
    return len(items) != len(set(items))

print(has_duplicates([1, 2, 3, 4]))       # False
print(has_duplicates([1, 2, 2, 3, 4]))    # True
print(has_duplicates(["a", "b", "a"]))    # True

3. Операции множеств

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(f"Объединение (union): {a | b}")          # {1, 2, 3, 4, 5, 6}
print(f"Пересечение (intersection): {a & b}")  # {3, 4}
print(f"Разница (difference): {a - b}")        # {1, 2}
print(f"Симметричная разница: {a ^ b}")        # {1, 2, 5, 6}

4. Поиск уникальных слов

text = "Python Python Java Java Java C++ Rust Python"
words = text.split()
unique_words = set(words)
print(f"Уникальные языки: {unique_words}")  # {'Python', 'Java', 'C++', 'Rust'}
print(f"Всего уникальных: {len(unique_words)}")  # 4

5. Кеш часто запрашиваемых значений

cached_queries = {("user", 123), ("post", 456), ("user", 789)}

if ("user", 123) in cached_queries:
    print("Результат уже в кеше")
else:
    print("Нужно запросить данные")

Производительность

# Set имеет O(1) средняя сложность для операций
import time

# Поиск в list — O(n)
list_data = list(range(1_000_000))
start = time.time()
if 999_999 in list_data:
    pass
print(f"List поиск: {time.time() - start:.6f}s")

# Поиск в set — O(1)
set_data = set(range(1_000_000))
start = time.time()
if 999_999 in set_data:
    pass
print(f"Set поиск: {time.time() - start:.6f}s")

Вывод

В set могут находиться:

  • Числа (int, float, complex)
  • Строки (str)
  • Кортежи (если содержат только хешируемые элементы)
  • Frozenset
  • Bytes
  • Bool, None
  • Пользовательские объекты с __hash__() и __eq__()
  • Dataclass с frozen=True

В set НЕ могут находиться:

  • Списки (list)
  • Словари (dict)
  • Обычные set (используй frozenset)
  • Другие изменяемые объекты

Правило: только хешируемые и неизменяемые объекты. Это обеспечивает эффективность set (O(1) для операций) и предотвращает логические ошибки в коде.

Что может находиться в set? | PrepBro