DEV Community

Ítalo Epifânio
Ítalo Epifânio

Posted on • Edited on

2 1

Objetos hashable em Python

Hash de objetos é uma representação númerica inteira que é obtida utilizando o dunder method __hash__. Compreender esse conceito ajuda a entender como as estruturas de dados Python funcionam, uma vez que o hash dos objetos são utilizados internamente pela linguagem.

Programadores Python costumam se deparar com o conceito de hash de objetos quando tentam armazenar um objeto sem hash em uma estrutura de dados da linguagem. Por exemplo:

from dataclasses import dataclass

@dataclass
class Pessoa:
    nome: str
    cpf: str

p = Pessoa(nome="Ítalo Epifânio", cpf="1010101010")
pessoas = set()
pessoas.add(p)
Enter fullscreen mode Exit fullscreen mode

O código acima define uma classe pessoa e um objeto p do tipo pessoa. Ao tentar adicionar uma pessoa ao conjunto pessoas o seguinte erro é lançado:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Pessoa'
Enter fullscreen mode Exit fullscreen mode

Isso acontece porque a estrutura de dados "conjunto" do Python utiliza o hash em suas tabelas internas para encontrar o valor do objeto rapidamente. Como nosso objeto não tem hash, o erro acima é lançado.

Para adicionar um hash a um objeto implementa-se as funções __hash__ e __eq__ simultaneamente (caso esteja utilizando Python 2 a função __ne__ também deve ser adicionada). No exemplo a seguir modificamos nossa classe anterior para adquirir essa propriedade.

@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)
Enter fullscreen mode Exit fullscreen mode

Agora o código consegue ser executado sem o erro anterior. Se executarmos print(pessoas) veremos que o conjunto contém o seguinte valor:

{Pessoa(nome='Ítalo Epifânio', cpf=1010101010)}
Enter fullscreen mode Exit fullscreen mode

Um objeto é dito hashable se o valor de hash nunca é modificado durante sua fase de vida
-- Python Docs

Apenas implementar os dunder métodos acima não garante que o objeto é hashable. É preciso garantir o valor de hash desse objeto jamais sejá alterado pois isso pode levar a comportamentos não esperados, por exemplo:

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')}
Enter fullscreen mode Exit fullscreen mode

Ao alterar o cpf do objeto p note que o objeto não é mais encontrado na estrutura de dados conjunto (a segunda chamada do print(p in pessoas) retorna falso) e quando lista-se os valores do conjunto pessoas nota-se que há ainda um valor lá.

Em resumo: você não pode basear hash de objetos em valores mutáveis. Se o atributo de um objeto pode ser modificado durante seu ciclo de vida comportamentos inesperados podem acontecer.

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay