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

Функция Python hash()
Python hash() — это встроенный метод, который возвращает хэш-значение объекта, если оно есть. Хэш-значения — это просто целые числа, которые используются для быстрого сравнения ключей словаря во время поиска в словаре. Проще говоря, хэш — это целое число фиксированного размера, которое идентифицирует конкретное значение. Обратите внимание, что приведенное выше определение является самым простым объяснением.
Укажем, что может означать фиксированный хэш?
- Одни и те же данные будут иметь одинаковое значение хэш-функции.
- Даже незначительное изменение исходных данных может привести к совершенно другому значению хэш-функции.
- Хэш получается из хеш-функции, которая отвечает за преобразование части заданной информации в закодированный хэш.
- Несколько объектов могут иметь намного больше, чем несколько хэш-значений, поэтому два объекта могут хэшироваться до одного и того же хэш-значения. Это называется коллизией хэшей. Это означает, что если два объекта имеют одинаковый хэш-код, они не обязательно имеют одинаковое значение.
- Объекты, хешированные с помощью hash(), необратимы, что приводит к потере информации.
- Метод hash() возвращает хешированные значения только для неизменяемых объектов. Следовательно, его можно использовать в качестве индикатора для проверки изменяемых/неизменяемых объектов.
Внутри метод hash() вызывает метод __hash__() объекта, который установлен по умолчанию для любого объекта. Мы рассмотрим это позже.
Хэш-коды чаще всего используются при сравнении ключей словаря. Хэш-код ключей словаря сравнивается, когда для конкретного ключа выполняется поиск в словаре. Сравнение хэша происходит намного быстрее, чем сравнение всех значений ключа, поскольку набор целых чисел, который хэш-функция отображает каждый ключ словаря, намного меньше, чем сам набор объектов.
Синтаксис
См. приведенный ниже синтаксис метода хэширования.
|
1 |
hash(object) |
Параметры
Параметр объекта, хэш-значение которого должно быть возвращено (integer, string, float).
См. приведенный ниже пример кода.
|
1 2 3 4 5 6 7 8 |
# app.py tuple_value =(21, 19, 18, 46, 29) # tuples are immutable list_value = [11, 21, 31, 41, 51] # list are mutable print("The tuple hash value is : " + str(hash(tuple_value))) print("The list hash value is : " + str(hash(list_value))) |
См. приведенный ниже вывод.

Кортеж — это неизменяемый объект, то есть мы можем создать хэш-значение из кортежа. Список — это изменяемый объект. Вот почему он выдает ошибку, как будто мы можем преобразовать список в хэш. Список является нехешируемым типом.
Возвращаемое значение из hash()
Функция hash() возвращает хэш-значение объекта, если оно есть. Если у объекта есть собственный метод __hash__(), он усекает возвращаемое значение до размера Py_ssize_t.
Как hash() работает в Python
См. следующий пример хэша в python.
|
1 2 3 4 5 6 7 |
# app.py value = 1921 print("The integer hash value is : ", hash(value)) valueA = 19.21 print("The float hash value is : ", hash(valueA)) |
В приведенном выше коде мы взяли два типа данных.
- Integer
- Float
Теперь хэш целого числа — это само целое число, но хэш числа с плавающей запятой несколько отличается. Например, см. приведенный ниже вывод.

Python hash() String
Давайте начнем создавать простые примеры и сценарии, в которых метод hash() может быть полезен.
В этом примере мы получим хэш-значение строки.
|
1 2 3 4 5 6 7 8 9 |
# app.py app = "Instagram" hash1 = hash(app) hash2 = hash(app) print("Hash 1: %s" % hash1) print("Hash 2: %s" % hash2) |
См. приведенный ниже вывод.

Оба вывода одинаковы, потому что мы использовали одну и ту же строку для хэша.
Вот существенная загвоздка: если вы повторно запустите тот же скрипт, хэш изменится, как показано ниже.

Как определить функцию hash() для пользовательских объектов
Функция hash() переопределяет функцию __hash()__. Стоит заметить, что не каждый объект можно хэшировать (изменяемые коллекции не хэшируются).
Мы также можем определить функцию __hash__() для нашего пользовательского класса. Но перед этим отметим несколько существенных моментов.
См. следующий пример.
- Хэшируемая реализация не должна выполняться для изменяемых коллекций, так как ключи коллекций должны быть неизменяемыми для хеширования.
- Нам не нужно определять собственную реализацию функции __eq()__, так как она определена для всех объектов.
См. следующий пример кода.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# app.py class Employee: def __init__(self, empno, name): self.empno = empno self.name = name def __eq__(self, other): return self.empno == other.empno and self.name == other.name def __hash__(self): return hash((self.empno, self.name)) employee = Employee(21, 'Krunal') print("The hash is: %d" % hash(employee)) |
Вывод:

Кейсы для реализации пользовательского хэша для объектов.
Хэш-реализация объектов
| __eq__() | __hash__() | Описание |
|---|---|---|
| Определено(по умолчанию) | Определено(по умолчанию) | Если оставить как есть, все объекты сравниваются неравными(кроме самих себя) |
| (Если изменяемый) Определено | Не следует определять | Реализация хэшируемой коллекции требует, чтобы хэш-значение ключа было неизменным. |
| Не определено | Не следует определять | Если __eq__() не определено, __hash__() не следует определять. |
| Определено | Не определено | Экземпляры класса нельзя использовать в качестве хэшируемой коллекции.
__hash__() неявно установлено в None. Вызывает исключение TypeError при попытке получить хэш. |
| Определено | Удержать от родителя | __hash__ = <ParentClass>.__hash__ |
| Определено | Не хочет хешировать | __hash__ = None
Вызывает исключение TypeError при попытке получить хэш. |
Почему изменяемый объект нельзя хэшировать
Как мы уже знаем, хэшировать можно только неизменяемый объект. Это ограничение, запрещающее хеширование изменяемого объекта, значительно упрощает хеш-таблицу. Разберемся как.
Если изменяемый объект разрешено хэшировать, нам нужно обновлять хэш-таблицу каждый раз, когда значение объекта обновляется. Это означает, что нам придется переместить объект. Это очень дорогостоящая операция.
В Python у нас есть два объекта, которые используют хэш-таблицы, словари и наборы:
- Словарь представляет собой хеш-таблицу и называется ассоциативным массивом. В словаре хэшируются только ключи, а не значения. Вот почему ключ словаря также должен быть неизменяемым объектом, а значениями может быть что угодно, даже изменяемый список.
- Набор содержит уникальные объекты, которые можно хэшировать. Если у нас есть нехэшируемые элементы, мы не можем использовать набор и вместо этого используем список.
