Функция hash() в Python — как работает
В этом уроке вы узнаете, как работает функция hash() в Python и о том, как переопределить метод __hash__ в пользовательском классе.
Пример хеш-функции в Python
Начнем с простого примера.
- Сначала определите класс Person с атрибутами name и age:
class Person: def __init__(self, name, age): self.name = name self.age = age
- Во-вторых, создайте два экземпляра класса Person:
p1 = Person('John', 22) p2 = Person('Jane', 22)
- В-третьих, покажите хеши объектов p1 и p2:
print(hash(p1)) print(hash(p2))
Выход:
110373112736 110373572343
Функция hash() принимает объект и возвращает значение хеш-функции в виде целого числа. Когда вы передаете объект функции hash(), Python выполнит специальный метод объекта __hash__.
Это означает, что когда вы передаете объект p1 в функцию hash():
hash(p1)
Python вызовет метод __hash__ объекта p1:
p1.__hash__()
По умолчанию __hash__ использует идентификатор объекта, а __eq__ возвращает True, если два объекта одинаковы. Чтобы переопределить это поведение по умолчанию, вы можете реализовать __eq__ и __hash__.
Если класс переопределяет метод __eq__, объекты класса становятся нехешируемыми. Это означает, что вы не сможете использовать объекты в типе сопоставления. Например, вы не сможете использовать их в качестве ключей словаря или элементов набора.
Следующий класс Person реализует метод __eq__:
class Person: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): return isinstance(other, Person) and self.age == other.age
Если вы попытаетесь использовать объект Person в наборе, вы получите сообщение об ошибке. Например:
members = { Person('John', 22), Person('Jane', 22) }
Python выдает следующую ошибку:
TypeError: unhashable type: 'Person'
Кроме того, объект Person теряет хеширование, поскольку если вы реализуете __eq__, для __hash__ устанавливается значение None. Например:
hash(Person('John', 22))
Ошибка:
TypeError: unhashable type: 'Person'
Чтобы сделать класс Person хешируемым, вам также необходимо реализовать метод __hash__:
class Person: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): return isinstance(other, Person) and self.age == other.age def __hash__(self): return hash(self.age)
Теперь у вас есть класс Person, который поддерживает равенство по возрасту и хешируется.
Чтобы Person хорошо работал в структурах данных, таких как словари, хеш класса должен оставаться неизменным. Для этого вы можете сделать атрибут age класса Person свойством, доступным только для чтения:
class Person: def __init__(self, name, age): self.name = name self._age = age @property def age(self): return self._age def __eq__(self, other): return isinstance(other, Person) and self.age == other.age def __hash__(self): return hash(self.age)