Médio Python
Dataclass com field e frozen
Enunciado
Crie uma dataclass Pessoa com os campos nome (str), idade (int) e tags (list[str]) que deve ter valor padrão vazio e não participar da comparação de igualdade. Torne a classe imutável (frozen). Instancie duas pessoas com as mesmas informações, mas tags diferentes, e mostre que são iguais. Tente modificar um atributo e mostre que gera erro.
Requisitos
- Usar @dataclass com frozen=True
- Usar field para o campo tags com default_factory=list e compare=False
- Demonstrar igualdade ignorando tags
- Demonstrar que atributos não podem ser modificados
Código inicial
from dataclasses import dataclass, field
# Defina a dataclass Pessoa aqui
# Crie duas pessoas com tags diferentes e compare
# Tente modificar um atributo e capture o erro
Saída esperada
p1 == p2? True
p1.tags = ['nova'] -> erro: cannot assign to field 'tags'
Ver dica
Para capturar o erro de atribuição, use try/except FrozenInstanceError.
Mostrar solução
from dataclasses import dataclass, field
@dataclass(frozen=True)
class Pessoa:
nome: str
idade: int
tags: list[str] = field(default_factory=list, compare=False)
p1 = Pessoa('Ana', 30, ['amiga'])
p2 = Pessoa('Ana', 30, ['colega'])
print(f'p1 == p2? {p1 == p2}')
try:
p1.tags = ['nova']
except Exception as e:
print(f'p1.tags = [\'nova\'] -> erro: {e}')
Passo a passo
- Importamos
dataclassefield. - Decoramos
Pessoacom@dataclass(frozen=True)para torná-la imutável. - Definimos os campos
nome,idadeetags. - Para
tags, usamosfield(default_factory=list, compare=False):default_factorycria uma lista nova a cada instância ecompare=Falseexclui o campo da comparação de igualdade. - Criamos duas pessoas com mesmos nome e idade, mas tags diferentes.
- Comparamos: como
tagsnão entra na comparação, são iguais. - Tentamos atribuir a
p1.tags; como a classe é frozen, isso levantaFrozenInstanceError. - Capturamos a exceção e imprimimos a mensagem.
Por que funciona
frozen=True impede a modificação de atributos após a criação, simulando imutabilidade. field permite personalizar o comportamento de cada campo, como valor padrão e participação na comparação. Juntos, eles permitem criar objetos seguros e com semântica clara.
Erros comuns
- Esquecer
default_factorye usartags: list = []: isso causaValueError: mutable default <class 'list'> for field tags is not allowed. - Tentar modificar um atributo de instância frozen sem capturar a exceção: o programa quebra.
- Achar que
compare=Falseafeta a impressão: ele só afeta__eq__e ordenação.
Outra forma de resolver
Poderia usar @dataclass(frozen=True) sem field e definir tags como tuple, que é imutável. Mas aí perderia a flexibilidade de lista.
Saída esperada
p1 == p2? True
p1.tags = ['nova'] -> erro: cannot assign to field 'tags'