Хешируемые объекты в Python

Хэш объектов — это целочисленное числовое представление, которое получается с помощью метода dunder __hash__. Понимание этой концепции помогает понять, как работают структуры данных Python, поскольку хэш объектов используется внутри.

Программисты Python часто сталкиваются с концепцией объектного хэша, когда пытаются сохранить объект без хэша в структуре данных языка. Например:

from dataclasses import dataclass

@dataclass
class Pessoa:
    nome: str
    cpf: str

p = Pessoa(nome="Ítalo Epifânio", cpf="1010101010")
pessoas = set()
pessoas.add(p)
Войдите в полноэкранный режим Выход из полноэкранного режима

Приведенный выше код определяет класс person и объект p типа person. При попытке добавить человека в набор person возникает следующая ошибка:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Pessoa'
Войдите в полноэкранный режим Выход из полноэкранного режима

Это происходит потому, что структура данных Python «set» использует хэш в своих внутренних таблицах для быстрого поиска значения объекта. Поскольку наш объект не имеет хэша, возникает вышеуказанная ошибка.

Для добавления хэша к объекту мы реализуем функции __hash__ и __eq__ одновременно (при использовании Python 2 необходимо также добавить функцию __ne__). В следующем примере мы модифицируем наш предыдущий класс, чтобы он приобрел это свойство.

@dataclass
class Pessoa:
    nome: str
    cpf: str

    def __hash__(self):
        return hash(self.cpf)

    def __eq__(self, other):
        mesma_classe = self.__class__ == other.__class__
        mesmo_cpf = self.cpf == other.cpf

        return mesma_classe and mesmo_cpf

p = Pessoa(nome="Ítalo Epifânio", cpf="101.010.101-01")
pessoas = set()
pessoas.add(p)
Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь код может быть выполнен без предыдущей ошибки. Если мы выполним команду print(people), то увидим, что массив содержит следующее значение:

{Pessoa(nome='Ítalo Epifânio', cpf=1010101010)}
Войдите в полноэкранный режим Выход из полноэкранного режима

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

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

p = Pessoa(nome="Ítalo Epifânio", cpf="101.010.101-01")
pessoas = set()
pessoas.add(p)
print(p in pessoas) # retorna True
p.cpf = "999.999.999-99"
print(p in pessoas) # retorna False
print(pessoas) # retorna {Pessoa(nome='Ítalo Epifânio', cpf='999.999.999-99')}
Войдите в полноэкранный режим Выход из полноэкранного режима

При изменении cpf объекта p обратите внимание, что объект больше не найден в структуре данных set (второй вызов print(p in people) возвращает false), а при перечислении значений набора people вы заметили, что там все еще есть значение.

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

Оцените статью
devanswers.ru
Добавить комментарий