Sobes.tech
Junior

O que é um hash e como é usado nos dicionários em Python?

sobes.tech IA

Resposta da IA

Hash (ou valor de hash) é um valor numérico de comprimento fixo calculado com base no conteúdo de um objeto através de uma função de hash. Uma boa função de hash garante a deterministicidade (o mesmo objeto sempre fornece o mesmo hash) e busca uma distribuição uniforme dos hashes para diferentes objetos.

Em Python, os dicionários (tipo dict) usam hashing para armazenar e procurar eficientemente pares de "chave-valor". As chaves devem ser hasháveis, ou seja, possuir o método __hash__() e serem imutáveis ou ter uma implementação de __eq__() e __hash__() que garanta que objetos iguais por __eq__ tenham o mesmo hash.

Processo de funcionamento de um dicionário com hashes:

  1. Inserção: Ao adicionar um par (chave, valor), o hash da chave é calculado. Com base no hash, é determinado um local aproximado (cesto ou "bucket") para armazenar esse par na memória. Se várias chaves tiverem o mesmo hash (colisão), os pares são armazenados nesse cesto, frequentemente em forma de lista ligada ou outro mecanismo de resolução de colisões.
  2. Busca: Ao procurar um valor por chave, o hash da chave fornecida é calculado. Usando o hash, o dicionário encontra rapidamente o cesto correspondente. Depois, dentro desse cesto, ocorre uma comparação das chaves (usando o método __eq__) para encontrar a chave correta e extrair seu valor associado.

Vantagens do uso de hashing:

  • Eficiência: Em média, as operações de inserção, remoção e busca em um dicionário são realizadas com uma complexidade de tempo constante O(1), independentemente do tamanho do dicionário.
  • Acesso rápido: O hash permite acessar rapidamente a localização prevista dos dados, evitando percorrer todos os elementos.

Restrições e características:

  • Chaves hasháveis: Como mencionado, as chaves devem ser hasháveis. Tipos mutáveis, como listas (list) e conjuntos (set), não são hasháveis por padrão e não podem ser usados como chaves de dicionário.
  • Colisões: Embora as funções de hash tentem minimizar colisões, elas podem ocorrer, o que pode desacelerar um pouco as operações no pior caso (afetando a constante em O(1)).
  • Ordem: Até Python 3.7, a ordem dos elementos em um dicionário dependia da ordem de inserção e dos hashes das chaves. A partir do Python 3.7, os dicionários mantêm a ordem de inserção das chaves como um efeito secundário da implementação, mas isso não faz parte do mecanismo de hashing.

Exemplo de um objeto hashable e não hashable:

# Objeto hashable (imutável)
string_key = "hello"
int_key = 123
tuple_key = (1, 2)

print(hash(string_key))
print(hash(int_key))
print(hash(tuple_key))

# Objeto não hashable (mutável)
list_key = [1, 2]
# print(hash(list_key)) # Isto causará um TypeError

# Exemplo de uso em um dicionário
my_dict = {
    string_key: "mundo",
    int_key: 456,
    tuple_key: "uma tupla"
}

print(my_dict[string_key])
print(my_dict[int_key])
print(my_dict[tuple_key])

Assim, o hash é um mecanismo fundamental que permite aos dicionários em Python alcançar alta performance nas operações, baseado no cálculo rápido da representação numérica da chave.