hash()

Содержание
Введение
Кастомный класс как ключ
Похожие статьи

Введение

hash(object) Return the hash value of the object (if it has one). Hash values are integers. They are used to quickly compare dictionary keys during a dictionary lookup. Numeric values that compare equal have the same hash value (even if they are of different types, as is the case for 1 and 1.0).

For objects with custom __hash__() methods, note that hash() truncates the return value based on the bit width of the host machine.

Официальная документация

python -c "help(hash)"

Help on built-in function hash in module builtins: hash(obj, /) Return the hash value for the given object. Two objects that compare equal must also have the same hash value, but the reverse is not necessarily true.

Помощь по встроенной функции hash в модуле builtins: hash(obj, /) Возвращает значение хеша для заданного объекта. Два объекта, которые сравниваются как равные, также должны иметь одинаковое значение хеша, но обратное не обязательно верно.

Сначала рассмотрим пример того как hash() возвращает одинаковое значение для одинаковых объектов.

a = 2 b = 2 print(a == b) print(f"{hash(a)} == {hash(b)} {hash(a) == hash(b)}")

True 2 == 2 True

Так как разные объекты не обязаны иметь разный хеш, рассмотрим пример того как hash() возвращает одинаковое значение для разных объектов.

print(hash(-1)) print(hash(-2)) print(hash(-3))

-2 -2 -3

hash() возвращает -1 в случае ошибки, поэтому при передаче -1 в качестве аргумента возвращается -2

Изучим как hash() возвращает одинаковое значение для одинаковых объектов.

a = 2 b = 2.0 print(a == b) print(f"{hash(a)} == {hash(b)} {hash(a) == hash(b)}") a = 2 b = "2" print(a == b) print(f"{hash(a)} == {hash(b)} {hash(a) == hash(b)}")

True 2 == 2 True False 2 == 8257152642364735767 False

Несмотря на то, что 2 и 2.0 это int и float для hash() они являются одинаковыми объектами так как a == b это True. А вот str "2" это уже другой объект.

Кастомный класс как ключ

Рассмотрим ещё один пример:

Создадим класс C, который ничего не делает и словарь , в котором экземпляр класса C будет ключом. Попытка вызвать метод __hash__() у этого словаря приведет к ошибке

class C: pass dct = {C(): 3} print(dct.__hash__())

TypeError: 'NonType' object is not callable

Если попробовать получить значение 3 по ключу С() - получится ошибка

class C: pass dct = {C(): 3} print(dct[C()])

print(dct[C()]) ~~~^^^^^ KeyError: <__main__.C object at 0x00000203B506E2A0>

Дело в том, что создается два экземпляра класса C: C() и C() это разные объекты с разным хешем.

Для наглядности добавим в класс C метод __init__(), который будет печатать __hash__()

class C: def __init__(self): print(f"my hash is: {self.__hash__()}") pass a = C() dct = {a: 3} print(dct[C()])

my hash is: 99176226130 my hash is: 99176226163 Traceback (most recent call last): File "C:\Users\ANDREI\spython\hash_demo.py", line 8, in <module> print(dct[C()]) ~~~^^^^^ KeyError: <__main__.C object at 0x0000017175D1D730>

Очевидно, что у C() и C() разный хеш.

Использовать такие объекты как ключ в словаре нельзя. В таком случае говорят, что объект не хешируемый (У него нет Hashability)

Обмануть интерпретатор, написав свой метод __hash__() возвращающий константу, не получится.

class C: def __init__(self): print(f"my hash is: {self.__hash__()}") def __hash__(self): return 99176226130 pass a = C() print(a.__hash__()) b = C() print(b.__hash__()) dct = {a: 3} print(dct[b])

KeyError: <__main__.C object at 0x00000175A5C6D940> my hash is: 99176226130 99176226130 my hash is: 99176226130 99176226130

В терминал выводится одинковый хеш, но обработка идёт старым способом.

Подозреваю что где-то в object __hash__() переписывается в случае кастомных изменений

Чтобы наш объект стал хешируемым , то есть таким, который можно использовать как ключ в словаре, потребуется написать не только кастомный метод __hash__() но и __eq__()

lass C: def __init__(self, x): self.x = x def __hash__(self): return hash((self.x,)) def __eq__(self, other): return isinstance(other, C) and self.x == other.x a = C(1) print(a.__hash__()) b = C(1) print(b.__hash__()) dct = {a: 3} print(dct[b])

-6644214454873602895 -6644214454873602895 3

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

class C: pass st = {C(), C()} st.__hash__()

TypeError: 'NonType' object is not callable

Хешируемость

Объект является хешируемым, если у него есть хеш-значение, которое никогда не меняется в течение его жизни (ему нужен метод __hash__()), и его можно сравнивать с другими объектами (ему нужен метод __eq__()).

Хешируемые объекты, которые сравниваются как равные, должны иметь одинаковое хеш-значение.

Хешируемость делает объект пригодным для использования в качестве ключа словаря и члена множества, поскольку эти структуры данных используют хеш-значение внутри.

Большинство неизменяемых встроенных объектов Python являются хешируемыми; изменяемые контейнеры (такие как списки или словари) не являются; неизменяемые контейнеры (такие как кортежи и frozensets) хешируются только если их элементы хешируются.

Объекты, являющиеся экземплярами пользовательских классов, хешируются по умолчанию.

Все они сравниваются как неравные (кроме самих себя), и их хеш-значение выводится из их id() .

Официальная документация

hashable An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() method). Hashable objects which compare equal must have the same hash value. Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally. Most of Python’s immutable built-in objects are hashable; mutable containers (such as lists or dictionaries) are not; immutable containers (such as tuples and frozensets) are only hashable if their elements are hashable. Objects which are instances of user-defined classes are hashable by default. They all compare unequal (except with themselves), and their hash value is derived from their id().

Автор статьи: Андрей Олегович

Похожие статьи
*args **kwargs
sys.argv: аргументы командной строки
Лямбда функции
Функции первого класса
Замыкания
Декораторы
Кэширование
if, elif, else
Методы
Итерация
Генераторы
Генераторы: Maintaining State
Встроенные фукнции: all()zip()

Поиск по сайту

Подпишитесь на Telegram канал @aofeed чтобы следить за выходом новых статей и обновлением старых

Перейти на канал

@aofeed

Задать вопрос в Телеграм-группе

@aofeedchat

Контакты и сотрудничество:
Рекомендую наш хостинг beget.ru
Пишите на info@urn.su если Вы:
1. Хотите написать статью для нашего сайта или перевести статью на свой родной язык.
2. Хотите разместить на сайте рекламу, подходящую по тематике.
3. Реклама на моём сайте имеет максимальный уровень цензуры. Если Вы увидели рекламный блок недопустимый для просмотра детьми школьного возраста, вызывающий шок или вводящий в заблуждение - пожалуйста свяжитесь с нами по электронной почте
4. Нашли на сайте ошибку, неточности, баг и т.д. ... .......
5. Статьи можно расшарить в соцсетях, нажав на иконку сети: