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

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

3.0 Senior🔥 101 комментариев
#Python Core#Другое

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

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

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

Хешируемый объект

Хешируемый объект (hashable object) — это объект в Python, который имеет неизменяемое хеш-значение и может использоваться в качестве ключа словаря или элемента множества (set). Это одна из фундаментальных концепций, которая влияет на работу с коллекциями данных.

Основные характеристики

Объект считается хешируемым, если он удовлетворяет двум условиям:

  1. Имеет метод __hash__() — возвращает целое число, которое остаётся постоянным в течение жизни объекта
  2. Имеет метод __eq__() — позволяет сравнивать объекты на равенство
  3. Неизменяем — объект не может быть изменён после создания (immutable)

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

# Примеры хешируемых типов
int_val = 42
str_val = "hello"
tuple_val = (1, 2, 3)
frozenset_val = frozenset([1, 2, 3])
bool_val = True
none_val = None

# Все они могут быть ключами словаря
my_dict = {
    42: "число",
    "hello": "строка",
    (1, 2, 3): "кортеж",
    frozenset_val: "frozen set"
}

print(my_dict[42])  # число
print(hash(str_val))  # -2566235476910504676

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

# Список нехешируемых типов
my_list = [1, 2, 3]
my_dict = {"a": 1}
my_set = {1, 2, 3}

# Попытка использовать как ключ вызовет ошибку
try:
    d = {my_list: "value"}  # TypeError
except TypeError as e:
    print(f"Ошибка: {e}")
    # Ошибка: unhashable type: list

try:
    s = {my_dict}  # TypeError
except TypeError as e:
    print(f"Ошибка: {e}")
    # Ошибка: unhashable type: dict

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

from dataclasses import dataclass

# Неправильно: класс по умолчанию хешируем, но сравнивается по id
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p1 = Point(1, 2)
p2 = Point(1, 2)

print(hash(p1))  # Работает
print(p1 == p2)  # False (разные объекты)

# Правильно: определяем __hash__ и __eq__
@dataclass(frozen=True)  # frozen=True делает объект immutable
class PointFrozen:
    x: int
    y: int

p3 = PointFrozen(1, 2)
p4 = PointFrozen(1, 2)

print(hash(p3))  # Работает
print(p3 == p4)  # True (одинаковые значения)

# Можно использовать как ключ
map_of_points = {p3: "точка А", p4: "точка А"}
print(len(map_of_points))  # 1 (они считаются одним ключом)

Практическое применение

# Удаление дубликатов в списке (сохраняя порядок)
def remove_duplicates(items):
    seen = set()
    result = []
    for item in items:
        if item not in seen:
            seen.add(item)
            result.append(item)
    return result

print(remove_duplicates([1, 2, 2, 3, 1, 4]))  # [1, 2, 3, 4]

# Подсчёт уникальных элементов
from collections import Counter
data = ["apple", "banana", "apple", "cherry", "banana"]
counts = Counter(data)  # Работает только с хешируемыми объектами
print(counts)  # Counter({apple: 2, banana: 2, cherry: 1})

# Кэширование функций
from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(30))  # Быстро благодаря кэшу

Важные правила

  • Если a == b, то hash(a) == hash(b) — это обязательное условие
  • Обратное не всегда верно — разные объекты могут иметь одинаковый хеш (коллизия)
  • Хешируемость влияет на производительность — операции в set и dict работают за O(1) благодаря хешированию
  • Изменение объекта может привести к потере доступа в словаре/множестве:
# Пример проблемы
my_dict = {(1, 2): "value"}
my_list = [1, 2]
my_list.append(3)

# Это работает
my_dict[(1, 2, 3)] = "new value"

# А это нет (если кортеж содержит список)
try:
    t = ([1, 2], 3)
except TypeError:
    pass  # Кортежи с изменяемыми элементами нельзя создать

Понимание хешируемости критически важно для эффективной работы со словарями и множествами в Python.

Что такое хешируемый объект? | PrepBro