Прежде чем ознакомиться с функцией hash()
в Python, давайте разберемся, что такое хеширование.
Что такое хеширование?
Хэширование - функция, осуществляющая преобразование массива входных данных произвольной длины в выходную битовую строку установленной длины, выполняемое определённым алгоритмом. Преобразование, производимое хеш-функцией, называется хешированием.
Концепция хэширования существует с хэш-таблицей. В хэш-таблицах данные хранятся в виде пар ключей и значений, где ключом являются входные данные, для которых получено соответствующее значение.
Процесс хэширования включает в себя преобразование заданного ключа в другое значение. Хэш-функция используется для генерации нового значения в соответствии с математическим алгоритмом. Результат хэш-функции известен как хеш-значение.
Что такое hash функция в Python?
hash()
в Python - это встроенная функция, которая используется для возврата хэш-значения данного объекта. Хэш-значения - это целые числа, которые полезны при сравнении ключей словаря во время поиска словаря, при котором поиск значения данного ключа в функции словаря. hash()
работает только для неизменяемых объектов.
Неизменяемые объекты в Python: bool,int, float, tuple, string, frozenset.
Синтаксис:
hash(object)
Аргументы:
- Функция принимает один объект в качестве аргумента, чтобы вернуть его хеш-значение.
Давайте рассмотрим примеры хеширования:
# Для чисел
print('Хеш-значение:', hash(23))
# Для чисел с плавающей точкой
print('Хеш-значение:', hash(29.30))
# Для строк
print('Хеш-значение:', hash('Kuban Cossacks'))
# Для кортежа
print('Хеш-значение:', hash(tuple((1, 2, 3, 4, 5))))
# Для неизменяемого множества
print('Хеш-значение:', hash(frozenset((1, 2, 3, 4, 5))))
Результаты:
>>> Хеш-значение: 23
>>> Хеш-значение: 691752902764109853
>>> Хеш-значение: -1969214143514591502
>>> Хеш-значение: -5659871693760987716
>>> Хеш-значение: -3779889356588604112
Если мы передадим изменяемый объект, например список (list), то получим ошибку: TypeError: unhashable type: 'list'
# Список (изменяемый объект)
print('Хеш-значение:', hash(list((1, 2, 3, 4, 5))))
Результат:
>>> Traceback (most recent call last):
>>> File "C:\Users\Razilator\Desktop\Projects\Coding\articles\hash\main.py", line 2, in <module>
>>> print('Хеш-значение:', hash(list((1, 2, 3, 4, 5))))
>>> TypeError: unhashable type: 'list'
Если сравнивать целочисленные значения с числами с плавающей точкой методом хеширования, они будут также равны между собой, как бы если бы мы указали просто 2 == 2.0
print(hash(23) == hash(23.0))
print(hash(29.0) == 29)
print(29 == hash(29.0))
Результат:
>>> True
>>> True
>>> True
Использование функции hash() в объектах:
Пример:
class Student:
def __init__(self, name, city):
self.name = name
self.city = city
student_1 = Student('Vladislav', 'Moscow')
student_2 = Student('Vladislav', 'Moscow')
print('Хеш-значение для student_1', hash(student_1))
print('Хеш-значение для student_2', hash(student_2))
if student_1 == student_2:
print('Один и тот-же студент')
else:
print('Разные студенты')
Результат:
>>> Хеш-значение для student_1 103001664509
>>> Хеш-значение для student_2 103001664497
>>> Разные студенты
Мы видим, что, хотя значения атрибутов обоих объектов одинаковы, результат сравнения двух объектов не равен. Что мы можем сделать, так это создать таможенный специальный метод, чтобы справиться с этим. Это специальный метод __eq__
, который будет сравнивать значения атрибутов и соответственно возвращать значение True
или False
.
class Student:
def __init__(self, name, city):
self.name = name
self.city = city
def __eq__(self, other):
return self.name == other.name and self.city == other.city
student_1 = Student('Vladislav', 'Moscow')
student_2 = Student('Vladislav', 'Moscow')
#print('Хеш-значение для student_1', hash(student_1))
#print('Хеш-значение для student_2', hash(student_2))
if student_1 == student_2:
print('Один и тот-же студент')
else:
print('Разные студенты')
Результат:
>>> Один и тот-же студент
Но если мы захотим узнать хеш-значение, то получим ошибку: TypeError: unhashable type: 'Student'
Чтобы преодолеть эту проблему, необходимо использовать метод __hash__()
class Student:
def __init__(self, name, city):
self.name = name
self.city = city
def __eq__(self, other):
return self.name == other.name and self.city == other.city
def __hash__(self):
return hash((self.name, self.city))
student_1 = Student('Vladislav', 'Moscow')
student_2 = Student('Vladislav', 'Moscow')
print('Хеш-значение для student_1', hash(student_1))
print('Хеш-значение для student_2', hash(student_2))
if student_1 == student_2:
print('Один и тот-же студент')
else:
print('Разные студенты')
Результат:
>>> Хеш-значение для student_1 6182727541821412174
>>> Хеш-значение для student_2 6182727541821412174
>>> Один и тот-же студент
И если мы изменим значения, то студенты не будут равны друг другу:
class Student:
def __init__(self, name, city):
self.name = name
self.city = city
def __eq__(self, other):
return self.name == other.name and self.city == other.city
def __hash__(self):
return hash((self.name, self.city))
student_1 = Student('Vladislav', 'Moscow')
student_2 = Student('Vladislav', 'Moscow')
student_2.name = 'Natali'
student_2.city = 'Tomsk'
print('Хеш-значение для student_1', hash(student_1))
print('Хеш-значение для student_2', hash(student_2))
if student_1 == student_2:
print('Один и тот-же студент')
else:
print('Разные студенты')
Результат:
>>> Хеш-значение для student_1 49386540312254370
>>> Хеш-значение для student_2 2735435424243624172
>>> Разные студенты