Imutabilidade e Hashability
Objetos hashable podem existir em conjuntos e como chaves de dicionário. A imutabilidade é a maneira usual de garantir estabilidade de hash - se o valor de um objeto mudar após a inserção, as buscas falharão silenciosamente.
Receita
key = (42, "ada") # tupla de hashables - OK
tags = frozenset(["a", "b"]) # conjunto hashable
# NÃO é hashable:
# bad = ([1, 2],) # lista dentro de tupla
# { [1, 2]: "x" } # lista como chaveQuando usar isso:
- Usando objetos como chaves de dicionário ou membros de conjunto
- Construindo caches com chaves baseadas em argumentos
- Projetando objetos de valor em modelos de domínio
- Depurando
TypeError: unhashable type
Exemplo de Trabalho
from dataclasses import dataclass
@dataclass(frozen=True)
class UserId:
value: int
def cache_key(*parts: object) -> tuple:
return tuple(parts)
def dedupe_records(records: list[tuple[str, int]]) -> list[tuple[str, int]]:
seen: set[tuple[str, int]] = set()
unique: list[tuple[str, int]] = []
for record in records:
if record not in seen:
seen.add(record)
unique.append(record)
return unique
class Point:
__slots__ = ("x", "y")
def __init__(self, x: int, y: int) -> None:
self.x = x
self.y = y
def __eq__(self, other: object) -> bool:
if not isinstance(other, Point):
return NotImplemented
return (self.x, self.y) == (other.x, other.y)
def __hash__(self) -> int:
return hash((self.x, self.y))
if __name__ == "__main__":
index: dict[UserId, str] = {UserId(1): "Ada"}
print(index[UserId(1)])
print(dedupe_records([("a", 1), ("a", 1), ("b", 2)]))O que isso demonstra:
dataclasscomfrozen=Trueé hashable quando os campos são hashable- Chaves de cache de tupla combinam partes hashable
- Classe personalizada implementa
__eq__e__hash__correspondentes __slots__reduz a memória para muitos objetos pequenos
Mergulho Profundo
Como Funciona
__hash__- Digest inteiro usado para localizar o bucket em uma tabela de hash.__eq__- A igualdade deve concordar com o hash: objetos iguais têm hash igual.- Built-ins Imutáveis -
int,str,bytes,tuple(se os elementos forem hashable),frozenset. - Built-ins Mutáveis -
list,dict,set,bytearray- sem hash estável. - Classes de Usuário - O hash de instância padrão é por
id, a menos que substituído.
Regras de Hashability
| Objeto | Hashable? |
|---|---|
tuple de hashables | Sim |
tuple contendo lista | Não |
frozenset | Sim |
set | Não |
frozen dataclass | Sim, se os campos forem hashable |
Notas do Python
# dataclasses com unsafe_hash gera __hash__ a partir dos campos
@dataclass(frozen=True)
class Coord:
x: int
y: int
# desabilita hash quando semânticas mutáveis são necessárias
@dataclass(eq=True, frozen=False)
class Buffer:
data: bytearrayArmadilhas
- Dataclass mutável em conjunto - Dataclass mutável → não hashable por padrão. Correção:
frozen=Trueou excluir de conjuntos. __eq__personalizado sem__hash__- Python define__hash__ = None. Correção: Implemente__hash__consistente ou use padrõesfunctools.cached_propertycom cuidado.- Hash muda quando os campos mudam - Viola o contrato de dicionário/conjunto. Correção: Use apenas objetos imutáveis como chaves.
- Floats NaN -
float('nan')é hashable, masnan != nan. Correção: Evite chaves NaN. - Tuplas com listas mutáveis dentro - Tupla é hashable, mas o conteúdo da lista pode mutar, quebrando invariantes se exposto. Correção: Não modifique mutáveis aninhados usados em chaves.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
id(obj) dict | Mapa de identidade para objetos mutáveis | Deduplicação baseada em valor |
json.dumps key | Chaves de dicionário serializáveis | Necessita de velocidade ou tipos não-JSON |
hashlib digest | Fingerprint de blob grande | Necessita de semântica de igualdade de objeto |
| Índice único de DB | Unicidade persistente | Pipeline apenas em memória |
FAQs
Por que lista não é hashable?
Listas mutam no local - o hash se tornaria inválido após a inserção em um conjunto/dicionário.
Dicionários são alguma vez hashable?
Não. Use frozenset de itens ou tupla de pares se precisar de uma chave hashable semelhante a um mapeamento.
frozen dataclass é sempre hashable?
Apenas se todos os campos forem hashable. Tipos de campo mutáveis bloqueiam o hashing.
Posso fazer hash da minha classe personalizada?
Sim, com __hash__ e __eq__ consistentes. Prefira dataclass congelada para registros.
O que é __hash__ = None?
Marca a classe explicitamente como não hashable - instâncias não podem ser chaves de conjunto/dicionário.
chave tuple vs frozenset?
Tupla para chave composta ordenada. Frozenset para conjuntos de tags não ordenados.
Hash é igual à identidade?
O hash de objeto padrão pode usar id; classes baseadas em valor devem implementar hash de valor.
lru_cache hash?
As chaves do cache usam o hash dos argumentos - os argumentos devem ser hashable.
bytearray é hashable?
Não - é mutável. Use bytes para chave binária hashable.
Membros Enum são hashable?
Sim - membros Enum são singletons com identidade e hash estáveis.
Relacionados
- Dicionários - requisitos de chave
- Conjuntos e Frozensets - uso de frozenset
- dataclasses - registros congelados
- Métodos Dunder / Mágicos - eq e hash
Versões da Pilha: Esta página foi escrita para Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.