Функция 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)
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *