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

В каких случаях кортеж не может быть хешируемым

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

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

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

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

# Когда кортеж не хешируем (не hashable)

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

Кортеж хешируем, только если все его элементы хешируемы.

Если кортеж содержит хотя бы один немутабельный (unhashable) элемент, сам кортеж становится немутабельным.

Примеры немутабельных типов

# ХЕШИРУЕМЫЕ (можно использовать как ключи в dict, элементы set)
hashable_types = [
    42,              # int
    3.14,            # float
    "hello",         # str
    True,            # bool
    None,            # NoneType
    (1, 2, 3),       # tuple из хешируемых элементов
    frozenset(),     # frozenset
]

# НЕМУТАБЕЛЬНЫЕ (нельзя использовать как ключи)
unhashable_types = [
    [1, 2, 3],           # list - мутабельный
    {'a': 1},            # dict - мутабельный
    {1, 2, 3},           # set - мутабельный
    (1, [2, 3], 4),      # tuple с списком внутри
    bytearray(),         # bytearray - мутабельный
]

Случай 1: Кортеж содержит список

# ❌ Немутабельный кортеж
tuple_with_list = (1, [2, 3], 4)

# Попытка использовать как ключ словаря
my_dict = {}
# my_dict[tuple_with_list] = "value"
# TypeError: unhashable type: 'list'

# Попытка добавить в set
# my_set = {tuple_with_list}
# TypeError: unhashable type: 'list'

# hash() вернет ошибку
# hash(tuple_with_list)
# TypeError: unhashable type: 'list'

Почему ошибка? Потому что список можно менять, а значит его хеш может измениться.

Случай 2: Кортеж содержит словарь

# ❌ Немутабельный кортеж
tuple_with_dict = ("key", {"name": "Alice"}, 42)

# my_dict[tuple_with_dict] = "value"
# TypeError: unhashable type: 'dict'

# my_set = {tuple_with_dict}
# TypeError: unhashable type: 'dict'

Случай 3: Кортеж содержит set

# ❌ Немутабельный кортеж
tuple_with_set = (1, {2, 3}, 4)

# my_dict[tuple_with_set] = "value"
# TypeError: unhashable type: 'set'

Случай 4: Кортеж содержит другой кортеж с немутабельным элементом

# ❌ Немутабельный кортеж (вложенные кортежи)
inner_tuple = (1, [2, 3])  # Это немутабельный кортеж
outer_tuple = (10, inner_tuple, 20)

# my_dict[outer_tuple] = "value"
# TypeError: unhashable type: 'list'
# Ошибка достает до вложенного кортежа, содержащего список

Случай 5: Кортеж содержит bytearray

# ❌ Немутабельный кортеж
tuple_with_bytearray = (1, bytearray(b"hello"), 2)

# my_dict[tuple_with_bytearray] = "value"
# TypeError: unhashable type: 'bytearray'

Как проверить, хешируем ли кортеж

Способ 1: Попробовать использовать как ключ

def is_hashable(obj):
    try:
        hash(obj)
        return True
    except TypeError:
        return False

# Примеры
print(is_hashable((1, 2, 3)))              # True
print(is_hashable((1, [2, 3], 4)))         # False
print(is_hashable(("hello", (1, 2))))      # True
print(is_hashable((1, {"a": 1})))          # False

Способ 2: Использовать collections.abc.Hashable

from collections.abc import Hashable

# ✅ Правильный способ
print(isinstance((1, 2, 3), Hashable))          # True
print(isinstance((1, [2, 3]), Hashable))        # False
print(isinstance([1, 2, 3], Hashable))          # False
print(isinstance({"a": 1}, Hashable))           # False
print(isinstance(frozenset([1, 2]), Hashable))  # True

Практические примеры

Пример 1: Кортеж как ключ словаря

# ✅ Хешируемый кортеж - работает
coordinates = {
    (0, 0): "origin",
    (1, 2): "point A",
    (3, 4): "point B",
}
print(coordinates[(1, 2)])  # point A

# ❌ Немутабельный кортеж - ошибка
# bad_coordinates = {
#     (0, [0]): "origin",  # TypeError!
# }

Пример 2: Кортеж в set

# ✅ Хешируемый кортеж - работает
unique_coords = {(0, 0), (1, 1), (2, 2)}
print((1, 1) in unique_coords)  # True

# ❌ Немутабельный кортеж - ошибка
# bad_set = {(0, 0), (1, [1]), (2, 2)}
# TypeError: unhashable type: 'list'

Пример 3: Функция с кортежом как параметр

# Функция для кеширования (используя dict)
def cache_result(func):
    cache = {}
    
    def wrapper(*args):
        # args - это кортеж аргументов
        if args in cache:  # args должен быть хешируем!
            return cache[args]
        
        result = func(*args)
        cache[args] = result
        return result
    
    return wrapper

@cache_result
def expensive_function(x, y):
    print(f"Вычисляю {x} + {y}")
    return x + y

print(expensive_function(1, 2))  # Вычисляю 1 + 2, результат: 3
print(expensive_function(1, 2))  # Из кэша: 3

# Если бы аргументы содержали список:
# def bad_function(x, items_list):  # items_list - список
#     # При вызове args будет (1, [1,2,3])
#     # Это немутабельный кортеж!
#     # TypeError при попытке использовать как ключ

Решения для немутабельных кортежей

Вариант 1: Заменить мутабельные элементы на иммутабельные

# ❌ Плохо - немутабельный кортеж
bad_tuple = (1, [2, 3], 4)

# ✅ Хорошо - заменяем список на кортеж
good_tuple = (1, (2, 3), 4)
print(hash(good_tuple))  # Работает!

# Использовать как ключ
my_dict = {good_tuple: "value"}
print(my_dict[good_tuple])  # value

Вариант 2: Заменить список на frozenset

# Если порядок не важен
bad_tuple = (1, [2, 3, 2], 4)
good_tuple = (1, frozenset([2, 3]), 4)
print(hash(good_tuple))  # Работает!

Вариант 3: Заменить словарь на что-то хешируемое

from types import SimpleNamespace

# ❌ Плохо
bad_tuple = (1, {"name": "Alice", "age": 30}, 2)

# ✅ Хорошо - использовать кортежи вместо dict
good_tuple = (1, (("name", "Alice"), ("age", 30)), 2)
print(hash(good_tuple))  # Работает!

# Или frozenset (если порядок не важен)
good_tuple2 = (1, frozenset([("name", "Alice"), ("age", 30)]), 2)
print(hash(good_tuple2))  # Тоже работает!

Таблица: Какие типы хешируемы

ТипХешируемМутабельныйПримеры
int42
float3.14
str"hello"
tuple✅ (если элементы хешируемы)(1, 2, 3)
frozensetfrozenset([1, 2])
list[1, 2, 3]
dict{"a": 1}
set{1, 2, 3}
bytearraybytearray(b"hi")

Вывод

Кортеж немутабельный, если содержит хотя бы один немутабельный элемент (список, словарь, set, bytearray и т.д.).

Проверить, хешируем ли кортеж, можно через:

  1. hash(tuple) — попытка захешировать
  2. isinstance(tuple, collections.abc.Hashable) — проверить тип

Если нужен кортеж как ключ или элемент set, убедись, что все его элементы иммутабельны. Заменяй списки на кортежи, словари на кортежи с парами, sets на frozenset.

В каких случаях кортеж не может быть хешируемым | PrepBro