Ответ
В Python ключом словаря может быть любой хешируемый (hashable) объект. Хешируемость означает, что объект имеет неизменяемое значение хеша на протяжении всей его жизни и может быть сравнен с другими объектами (имеет методы __hash__() и __eq__()).
Основные хешируемые (допустимые) типы:
- Неизменяемые встроенные типы:
int,float,str,bytes,tuple,frozenset,bool. - Пользовательские классы: Экземпляры пользовательских классов по умолчанию хешируемы (хеш основан на
id()). Однако, если вы переопределите__eq__(), то должны также явно определить__hash__()для сохранения хешируемости.
Нехешируемые (недопустимые) типы:
- Изменяемые коллекции:
list,set,dict. - Массивы NumPy и другие изменяемые объекты.
Почему это важно? Словарь внутри реализован как хеш-таблица. При вставке пары ключ-значение вычисляется хеш ключа, который определяет "ячейку" для быстрого поиска. Если бы ключ мог измениться, его хеш тоже изменился бы, и найти связанное с ним значение стало бы невозможно.
Примеры:
# Допустимые ключи
valid_dict = {
42: 'integer',
3.14: 'float',
'hello': 'string',
(1, 2, 3): 'tuple of integers',
('a', ('b', 'c')): 'nested tuple',
frozenset([1, 2]): 'frozenset',
True: 'boolean (подтип int)',
MyImmutableClass(): 'пользовательский класс'
}
# Вызовет TypeError: unhashable type
invalid_dict = {
[1, 2]: 'list', # НЕЛЬЗЯ
{'a': 1}: 'dict', # НЕЛЬЗЯ
{1, 2}: 'set' # НЕЛЬЗЯ
}
# Кортеж может быть ключом, только если все его элементы хешируемы
good_tuple_key = (1, 'a', (2, 3)) # ОК
bad_tuple_key = (1, [2, 3]) # TypeError, т.к. содержит список Ответ 18+ 🔞
А, слушай, вот тебе на самом деле важная штука, которую многие на первых порах проёбывают. Речь про то, что можно, а что нельзя пихать в ключи словаря в Python. Запомни раз и навсегда, чтобы потом не охуевать от ошибок.
Короче, ключом может быть только хешируемый объект. Что это значит на нормальном языке? Это значит, что у объекта есть какое-то неизменное, постоянное значение хеша, которое не меняется, пока объект живёт, и его можно сравнивать с другими. Технически — у него должны быть методы __hash__() и __eq__(). Если этого нет — забудь, это не ключ.
Что можно пихать в ключи (хешируемое):
- Всё неизменяемое и встроенное:
int,float,str,bytes,tuple,frozenset,bool. Да,TrueиFalse— это, по сути, те же самые единичка и ноль, так что они тоже катят. - Свои классы: Да, экземпляры твоих собственных классов по умолчанию тоже хешируемы. Но тут есть подвох, ёпта! Если ты вдруг начнёшь умничать и переопределишь метод
__eq__()для сравнения, то ты обязан явно прописать и__hash__(), иначе всё накроется медным тазом и хешируемость потеряется. Не забывай об этом, а то будет тебе хиросима.
Что НЕЛЬЗЯ пихать в ключи (нехешируемое):
- Всё изменяемое:
list,set,dict. Вот эти ребята — распиздяи, их внутренности могут меняться, поэтому они не годятся. - Массивы NumPy и прочая изменяемая хрень.
А почему, собственно, нельзя? Да потому что словарь внутри — это хеш-таблица, ядрёна вошь! Когда ты добавляешь пару, Python быстренько вычисляет хеш от ключа, чтобы понять, в какую ячейку положить значение для потом быстрого поиска. Представь, что ты положил список как ключ, а потом его изменил. Его хеш поменяется, и как потом искать значение, которое ты к нему привязал? Да никак! Поэтому Python просто не даёт тебе такой возможности, чтобы не было пиздеца.
Примеры, чтобы совсем понятно стало:
# Вот это всё работает — кладём спокойно
valid_dict = {
42: 'integer',
3.14: 'float',
'hello': 'string',
(1, 2, 3): 'tuple of integers',
('a', ('b', 'c')): 'nested tuple',
frozenset([1, 2]): 'frozenset',
True: 'boolean (подтип int)',
MyImmutableClass(): 'пользовательский класс'
}
# А вот это вызовет TypeError: unhashable type — готовься к ошибке
invalid_dict = {
[1, 2]: 'list', # НИНАДА
{'a': 1}: 'dict', # АБСОЛЮТНО НИНАДА
{1, 2}: 'set' # ЗАБУДЬ
}
# С кортежами отдельная история. Сам кортеж неизменяемый, но он может быть ключом ТОЛЬКО если ВСЕ его элементы тоже хешируемы.
good_tuple_key = (1, 'a', (2, 3)) # ОК, всё неизменяемое внутри
bad_tuple_key = (1, [2, 3]) # Ошибка! Потому что внутри сидит изменяемый список, пидарас шерстяной.
Вот и вся магия. Главное — запомни принцип: ключ должен быть неизменным. Всё, что может поменяться после создания, — это манда с ушами для ключа словаря. Доверия к таким объектам — ноль ебать.