Какие значения могут быть ключами словаря?

Рейтинг: 11Ответов: 1Опубликовано: 27.01.2023

Документация гласит, что ключами могут быть только неизменяемые типы данных. Почему в данном случае не возникает ошибка?

class Test:
    pass

t = Test()
print({t: 1})

Ответы

▲ 9Принят

Попробую ответить, т.к. вопрос интересный и сам не знал почему.

Коротко: причина в наличии магическом методе __hash__

Если мы используем словарь как ключ:

t = dict()
d = {t: 1}

То получаем ошибку:

TypeError: unhashable type: 'dict'

Но, вообще-то, эту же ошибку получим, если попробуем получить хеш:

t = dict()
print(hash(t))

У не хешируемых типов, магический метод __hash__ отсутствует:

t = dict()
print(t.__hash__)
# None

Вот так выглядит наличие этого метода:

print(Test.__hash__)
# <slot wrapper '__hash__' of 'object' objects>

t = Test()
print(t.__hash__)
# <method-wrapper '__hash__' of Test object at ...

Мы это легко проверим на нашем классе Test:

class Test:
    __hash__ = None

t = Test()
d = {t: 1}

Знакомая ошибка:

TypeError: unhashable type: 'Test'

ℹ️ Выходит, что у классов, по-умолчанию, есть метод __hash__, поэтому их можно использовать в ключах словаря и в других местах (типа множеств), реализованных через хеши


Кст, по-умолчанию, хеш высчитывается из id объекта деленного на 16.

Тут будет одинаковый результат:

class Test:
    pass

t = Test()

print(hash(t))
print(hash(id(t) // 16))