
Passo 1 de 9
Declarar um objeto de dados
Crie uma dataclass simples para representar uma tarefa e reconheça os métodos gerados a partir dos campos declarados.
Trilha de aprendizado · Nível 11 · Tutorial 8
Ao concluir, você poderá usar dataclasses para reduzir código repetitivo em objetos de dados, controlando inicialização, representação, comparação e comportamento de hash.
Declarar um objeto de dados
Crie uma dataclass simples para representar uma tarefa e reconheça os métodos gerados a partir dos campos declarados. 2 min
Combinar campos obrigatórios e valores padrão
Organize os campos de uma dataclass para criar instâncias com argumentos obrigatórios e padrões previsíveis. 2 min
Criar coleções independentes com default_factory
Crie listas de etiquetas separadas para cada instância e reconheça quando uma lista ainda é compartilhada por escolha explícita. 3 min
Validar a construção com __post_init__
Normalize e valide uma Tarefa logo após a inicialização gerada pela dataclass. 3 min
Escolher o que aparece e o que define igualdade
Controle separadamente os campos exibidos por uma dataclass e os campos que definem a igualdade entre instâncias. 3 min
Gerar uma ordenação coerente com o domínio
Configure comparações de ordem geradas e use a sequência dos campos participantes para definir uma ordem natural de tarefas. 3 min
Entender os limites de frozen
Veja o que uma dataclass congelada bloqueia — e por que uma lista interna ainda pode mudar. 3 min
Prever a disponibilidade de hash
Use eq e frozen para decidir quando uma dataclass pode participar de conjuntos e ser chave de dicionários. 4 min
Aplicar as decisões em um modelo completo
Reúna as decisões de modelagem em uma classe mutável e em uma chave congelada, verificando os comportamentos no seu computador. 4 min

Passo 1 de 9
Crie uma dataclass simples para representar uma tarefa e reconheça os métodos gerados a partir dos campos declarados.
Quando uma classe serve principalmente para guardar dados, uma dataclass pode gerar automaticamente métodos comuns. Importe o decorador da biblioteca padrão e aplique-o à classe com @dataclass.
Uma Tarefa tem dois campos: título e prioridade.
from dataclasses import dataclass
@dataclass
class Tarefa:
titulo: str
prioridade: intOs campos anotados orientam a criação dos métodos padrão.

Sem escrever esses métodos, a dataclass gera inicialização, representação e igualdade a partir dos campos.
Nesta classe, titulo e prioridade viram argumentos do __init__ gerado. A representação também mostra os valores dos campos.
Execute este código no seu editor ou no interpretador Python.
tarefa = Tarefa("Enviar relatório", 2)
print(tarefa)
print(tarefa == Tarefa("Enviar relatório", 2))
print(tarefa == Tarefa("Enviar relatório", 3))
# Saída esperada:
# Tarefa(titulo='Enviar relatório', prioridade=2)
# True
# FalseDica
Sem uma implementação própria, a dataclass fornece __init__, __repr__ e __eq__. Assim, você constrói o objeto, obtém uma representação informativa e compara tarefas pelos dados declarados.
As anotações declaram os campos para a dataclass, mas não verificam nem convertem automaticamente os argumentos em tempo de execução. Portanto, este código é aceito na construção, embora o valor não corresponda ao tipo indicado:
tarefa_estranha = Tarefa("Enviar relatório", "alta")
print(tarefa_estranha)
# Tarefa(titulo='Enviar relatório', prioridade='alta')Atenção
prioridade: int documenta que a prioridade deve ser um inteiro; não impede, sozinha, que uma string seja passada. A validação durante a construção será tratada mais adiante.
Relacione cada operação com o método que a dataclass gera para esta classe.
Toque em um item e depois no par correspondente.

Passo 2 de 9
Organize os campos de uma dataclass para criar instâncias com argumentos obrigatórios e padrões previsíveis.
Em uma dataclass, um campo sem valor padrão se torna um argumento obrigatório do __init__ gerado. Um campo com = recebe um padrão e pode ser omitido na construção.
Na declaração básica, coloque todos os campos obrigatórios antes dos campos com padrão. Essa ordem permite que o inicializador tenha uma assinatura válida e previsível.
A ordem dos campos é preservada nos argumentos gerados.

Campos declarados de cima para baixo: primeiro os obrigatórios; depois os que têm padrão.
Crie este arquivo e execute-o no seu computador.
from dataclasses import dataclass
@dataclass
class Tarefa:
titulo: str
prioridade: int
concluida: bool = False
primeira = Tarefa("Estudar dataclasses", 1)
segunda = Tarefa("Enviar relatório", 2, True)
terceira = Tarefa(titulo="Revisar código", prioridade=3, concluida=True)
print(primeira)
print(segunda)
print(terceira)Exemplo
primeira usa o padrão: concluida=False.
segunda substitui o padrão com o terceiro argumento posicional: concluida=True.
terceira faz a mesma substituição com argumentos nomeados. A ordem da classe corresponde à assinatura conceitual Tarefa(titulo, prioridade, concluida=False).
Dica
Use valores simples, como False, 0 ou uma string, diretamente após =. Coleções mutáveis, como listas, exigem outro recurso, visto no próximo step.
Reorganize as linhas para que esta dataclass gere um inicializador válido. Considere que titulo deve ser obrigatório e concluida deve começar como False.

Passo 3 de 9
Crie listas de etiquetas separadas para cada instância e reconheça quando uma lista ainda é compartilhada por escolha explícita.
Use field para configurar um campo de dataclass quando um valor padrão precisa ser criado para cada instância. Listas e dicionários são mutáveis: se fossem compartilhados como padrão, uma alteração em uma tarefa poderia aparecer em outra.
Por isso, dataclasses rejeitam uma lista ou um dicionário escrito diretamente como valor padrão de um campo. A solução é default_factory.
Cada construção sem argumento para etiquetas aciona uma nova criação de lista.

Com default_factory=list, cada tarefa recebe sua própria lista de etiquetas.
Atenção
Escreva default_factory=list, e não default_factory=list(). A fábrica recebe um chamável sem argumentos; o __init__ gerado chamará list() quando for necessário criar o padrão.
Digite e execute este exemplo no seu editor ou no interpretador Python.
from dataclasses import dataclass, field
@dataclass
class Tarefa:
titulo: str
concluida: bool = False
etiquetas: list[str] = field(default_factory=list)
primeira = Tarefa("Enviar relatório")
segunda = Tarefa("Revisar orçamento")
primeira.etiquetas.append("urgente")
print(primeira.etiquetas) # ['urgente']
print(segunda.etiquetas) # []
print(primeira.etiquetas is segunda.etiquetas) # FalseAo omitir etiquetas, o inicializador gerado chama list() para aquela construção. Assim, primeira.etiquetas e segunda.etiquetas são objetos distintos. O campo continua aceitando uma lista fornecida explicitamente por quem cria a tarefa.
No código anterior, adicione mais uma etiqueta a primeira.etiquetas e execute novamente. O que acontece com segunda.etiquetas? Explique o resultado usando default_factory.
Escreva pelo menos 80 caracteres (0/80).
Agora execute este complemento após o código anterior.
etiquetas_da_equipe = ["financeiro"]
terceira = Tarefa("Conferir nota", etiquetas=etiquetas_da_equipe)
quarta = Tarefa("Arquivar comprovante", etiquetas=etiquetas_da_equipe)
terceira.etiquetas.append("mensal")
print(quarta.etiquetas) # ['financeiro', 'mensal']
print(terceira.etiquetas is quarta.etiquetas) # Truedefault_factory só é usado quando o argumento etiquetas é omitido. Ao passar etiquetas_da_equipe para as duas tarefas, você fornece a mesma lista às duas instâncias. Não há cópia automática; por isso, alterar uma referência altera o conteúdo visto pela outra.
Qual é o resultado de a.etiquetas is b.etiquetas neste código?
a = Tarefa("A")
b = Tarefa("B")
Passo 4 de 9
Normalize e valide uma Tarefa logo após a inicialização gerada pela dataclass.
Em uma dataclass, o inicializador gerado recebe os argumentos e atribui os campos à instância. Se a classe define __post_init__, ele é chamado automaticamente em seguida.
Esse método é um bom lugar para ajustar valores e verificar regras do domínio que precisam ser verdadeiras no momento da construção.
A normalização acontece antes das verificações que dependem do valor ajustado.

Argumentos → campos atribuídos → __post_init__. Se uma regra falhar, a construção termina com uma exceção.
strip() remove espaços no início e no fim antes de testar se restou conteúdo.
from dataclasses import dataclass, field
@dataclass
class Tarefa:
titulo: str
prioridade: int = 0
etiquetas: list[str] = field(default_factory=list)
def __post_init__(self):
self.titulo = self.titulo.strip()
if not self.titulo:
raise ValueError("o título não pode ficar vazio")
if self.prioridade < 0:
raise ValueError("a prioridade não pode ser negativa")
tarefa = Tarefa(" Revisar relatório ", prioridade=2)
print(tarefa.titulo) # Revisar relatórioDica
Primeiro normalize o título; depois teste se ele ficou vazio. Assim, uma entrada como " " não passa pela validação só porque continha espaços.
No método abaixo, complete a expressão para rejeitar prioridades negativas:
if self.prioridade ___ 0:
raise ValueError("a prioridade não pode ser negativa")A chamada automática acontece quando Tarefa(...) cria a instância. Depois disso, uma atribuição comum a um campo não chama __post_init__ novamente.
Por exemplo, tarefa.prioridade = -1 altera o atributo sem disparar a validação acima. Portanto, __post_init__ protege a entrada na construção, não todas as mudanças futuras.
Para cada situação, diga se uma instância é criada, qual título fica armazenado ou qual exceção ocorre. Inclua também o que acontece depois em uma alteração posterior:
Tarefa(" Planejar ", 1)
Tarefa(" ", 1)
Tarefa("Ler", -1)
existente = Tarefa("Estudar", 0)
existente.prioridade = -1Escreva pelo menos 80 caracteres (0/80).

Passo 5 de 9
Controle separadamente os campos exibidos por uma dataclass e os campos que definem a igualdade entre instâncias.
Por padrão, a dataclass gera __repr__ e __eq__ usando seus campos. Com field, você pode decidir separadamente se um campo aparece na representação (repr) e se participa da igualdade (compare).
Isso é útil para etiquetas: elas podem ser metadados da tarefa, sem definir se duas tarefas representam o mesmo valor.
A representação e a igualdade consultam configurações distintas.

repr controla a aparência em repr(objeto); compare controla os campos usados por ==.
Use repr=False e compare=False no mesmo campo quando ele não deve aparecer nem definir igualdade.
from dataclasses import dataclass, field
@dataclass
class Tarefa:
titulo: str
prioridade: int = 0
etiquetas: list[str] = field(
default_factory=list,
repr=False,
compare=False,
)
primeira = Tarefa("Revisar relatório", 2, ["trabalho"])
segunda = Tarefa("Revisar relatório", 2, ["urgente"])
print(primeira)
# Tarefa(titulo='Revisar relatório', prioridade=2)
print(primeira == segunda)
# True
print(primeira.etiquetas)
# ['trabalho']Dica
repr=False não protege nem esconde o atributo: primeira.etiquetas continua funcionando normalmente. Ele só o remove da representação gerada.
Exemplo
Se usar apenas repr=False, as etiquetas somem de repr(tarefa), mas ainda participam de tarefa1 == tarefa2.
Se usar apenas compare=False, elas aparecem na representação, mas são ignoradas na igualdade.
Use ambas as opções somente quando quiser os dois efeitos.
Com o padrão eq=True, a igualdade gerada compara os campos cujo compare é verdadeiro, mas apenas entre instâncias do mesmo tipo concreto. Assim, uma instância de Tarefa não é igual a uma instância de outra classe, mesmo que os valores dos atributos pareçam iguais.
No decorador, repr=False impede a geração de __repr__, e eq=False impede a geração de __eq__. Essas opções não removem uma implementação que já exista na hierarquia da classe; apenas dizem à dataclass para não gerar aquele método.
Considere etiquetas: list[str] = field(default_factory=list, repr=False). Duas Tarefa têm o mesmo título e prioridade, mas listas de etiquetas diferentes. Qual resultado é esperado para tarefa1 == tarefa2?
Relacione cada objetivo à configuração adequada para o campo etiquetas.
Toque em um item e depois no par correspondente.

Passo 6 de 9
Configure comparações de ordem geradas e use a sequência dos campos participantes para definir uma ordem natural de tarefas.
Uma dataclass comum gera igualdade, mas não cria automaticamente métodos como < e >. Portanto, comparar duas tarefas com < falha até que você peça essa geração.
Use order=True no decorador para gerar __lt__, __le__, __gt__ e __ge__. Essa opção depende de eq=True: não é válido solicitar ordenação com eq=False.
Prioridade menor vem primeiro; em empate, o título decide.
from dataclasses import dataclass, field
@dataclass(order=True)
class Tarefa:
prioridade: int
titulo: str
etiquetas: list[str] = field(default_factory=list, compare=False)
primeira = Tarefa(1, "Enviar proposta")
segunda = Tarefa(2, "Revisar orçamento")
print(primeira < segunda) # TrueA ordem segue os campos declarados que participam da comparação.

Com order=True, a comparação é lexicográfica: prioridade, depois título. Como etiquetas usa compare=False, ela não participa.
Os campos participantes são consultados na ordem em que aparecem na classe, como numa comparação de tuplas. Para Tarefa, o critério é equivalente a comparar (prioridade, titulo).
Assim, prioridade é o critério principal e título só resolve empates. As etiquetas não influenciam a ordem porque foram declaradas com compare=False.
Exemplo
planejar = Tarefa(1, "Planejar reunião", ["equipe"])
apresentar = Tarefa(1, "Apresentar resultado", ["urgente"])
print(apresentar < planejar) # TrueAs prioridades empatam. Então os títulos são comparados: “Apresentar resultado” vem antes de “Planejar reunião” em ordem lexicográfica.
Dica
As comparações de ordem geradas se aplicam a instâncias do mesmo tipo concreto. Não trate uma Tarefa como ordenável em relação a um objeto de outra classe, mesmo que ele tenha campos parecidos.
Considere a classe Tarefa definida com @dataclass(order=True) e os campos prioridade, titulo e etiquetas, nesta ordem. etiquetas usa compare=False. Organize as instâncias da menor para a maior.
Qual opção tenta gerar uma ordenação de modo inválido?
Resumo
Use uma ordem que expresse o domínio.
order=True, a dataclass não gera comparações de ordem.order=True, os campos participantes são comparados na ordem da declaração.compare=False exclui um campo tanto da igualdade quanto da ordenação geradas.prioridade define o critério principal e titulo resolve empates.order=True exige eq=True.
Passo 7 de 9
Veja o que uma dataclass congelada bloqueia — e por que uma lista interna ainda pode mudar.
Ao usar @dataclass(frozen=True), a instância é construída normalmente, mas seus campos não podem ser atribuídos nem removidos pelas operações usuais depois da construção. Isso é útil quando o objeto deve representar um valor estável.
A camada congelada protege a referência armazenada no campo; ela não congela automaticamente o objeto para o qual essa referência aponta.

frozen=True bloqueia trocar ou remover o campo; não torna profundamente imutável o valor guardado nele.
Crie esta classe em um arquivo Python e execute os exemplos nas próximas telas.
from dataclasses import dataclass
@dataclass(frozen=True)
class TarefaCongelada:
titulo: str
etiquetas: list[str]
tarefa = TarefaCongelada("Estudar dataclasses", ["python"])
print(tarefa)Depois de criada, a tentativa de substituir titulo, substituir etiquetas ou remover um desses campos gera FrozenInstanceError. Essa exceção indica que a operação tentou alterar a estrutura da instância congelada.
Execute uma operação por vez para observar a exceção.
from dataclasses import FrozenInstanceError
try:
tarefa.titulo = "Revisar dataclasses"
except FrozenInstanceError as erro:
print(type(erro).__name__)
try:
tarefa.etiquetas = ["revisão"]
except FrozenInstanceError as erro:
print(type(erro).__name__)
try:
del tarefa.titulo
except FrozenInstanceError as erro:
print(type(erro).__name__)O campo etiquetas continua apontando para a mesma lista criada ou recebida na construção. Portanto, chamar um método mutável da própria lista, como append, altera seu conteúdo sem reatribuir o campo.
Este código não tenta substituir etiquetas; ele modifica a lista já armazenada.
tarefa.etiquetas.append("modelo")
print(tarefa.etiquetas)
# ['python', 'modelo']Atenção
frozen=True não torna listas, dicionários ou outros objetos mutáveis internos imutáveis. Se o modelo precisa representar um valor estável, prefira campos com valores imutáveis — por exemplo, uma tupla de etiquetas — e evite expor objetos mutáveis que possam ser alterados.
Em uma instância de TarefaCongelada, tarefa.etiquetas.append("urgente") gera FrozenInstanceError.

Passo 8 de 9
Use eq e frozen para decidir quando uma dataclass pode participar de conjuntos e ser chave de dicionários.
Quando você não define __hash__, a dataclass decide seu comportamento a partir de eq e frozen:
eq=True e frozen=False (o padrão): define __hash__ como None. A instância não é hashável.eq=True e frozen=True: gera __hash__ usando os campos que participam da comparação.eq=False: não altera o hash herdado, com ou sem frozen=True. Em uma classe que deriva diretamente de object, o hash continua baseado na identidade.A primeira regra evita usar como chave um objeto mutável cuja igualdade pode mudar depois de inserido em um dicionário ou conjunto.
Compare as três configurações mais comuns.

eq=True exige estabilidade para que a dataclass gere hash automaticamente; frozen=True fornece essa restrição sobre os campos.
Uma chave congelada com str e int pode ser usada em um conjunto.
from dataclasses import dataclass
@dataclass(frozen=True)
class ChaveTarefa:
prioridade: int
titulo: str
chave = ChaveTarefa(1, "Enviar relatório")
pendentes = {chave}
print(hash(chave))
print(chave in pendentes) # TrueComo eq=True é padrão, ChaveTarefa compara prioridade e titulo. Como também é congelada, a dataclass gera um hash compatível com esses campos.
Um campo com compare=False fica fora da igualdade e, por padrão, também fica fora do hash gerado. Assim, metadados que não definem o valor da chave não precisam influenciar sua identificação.
Execute este exemplo no seu computador.
from dataclasses import dataclass
@dataclass(frozen=True)
class TarefaComEtiquetas:
titulo: str
etiquetas: list[str]
tarefa = TarefaComEtiquetas("Revisar proposta", ["trabalho"])
print(hash(tarefa)) # TypeError: unhashable type: 'list'Atenção
A classe acima recebe um __hash__ gerado porque usa eq=True e frozen=True. Porém, etiquetas participa da comparação e do hash por padrão, e uma list não é hashável. Por isso, hash(tarefa) lança TypeError.
Além disso, frozen=True bloqueia trocar o campo etiquetas, mas não impede operações como tarefa.etiquetas.append("urgente"). Não trate congelamento como imutabilidade profunda.
A referência ao campo não pode ser substituída; o conteúdo da lista ainda pode mudar.

Para chaves e elementos de conjunto, escolha campos participantes hasháveis e com valores estáveis.
Relacione cada configuração ao comportamento de hash mais provável.
Toque em um item e depois no par correspondente.
Resumo
Antes de colocar uma dataclass em um set ou como chave de dict, avalie igualdade, congelamento e os valores dos campos participantes.
frozen=True com eq=True permite gerar hash, desde que os campos participantes sejam hasháveis.compare=False exclui um campo da igualdade e, por padrão, do hash gerado.TypeError, mesmo em uma dataclass congelada.
Passo 9 de 9
Reúna as decisões de modelagem em uma classe mutável e em uma chave congelada, verificando os comportamentos no seu computador.
Use Tarefa para o objeto que muda durante o trabalho: ela tem título, prioridade, estado de conclusão e etiquetas. Para agrupamento em conjuntos, use ChaveTarefa, menor e congelada.
Em Tarefa, apenas prioridade e titulo definem igualdade e ordenação. As etiquetas são metadados: não aparecem no repr nem participam das comparações.

A classe mutável concentra o estado de trabalho; a chave congelada reúne somente valores estáveis e hasháveis.
Crie um arquivo chamado modelo_tarefa.py, copie o código completo abaixo e execute python modelo_tarefa.py. Se todos os assert passarem, o script termina sem mostrar erro.
from dataclasses import dataclass, field
@dataclass(order=True)
class Tarefa:
prioridade: int
titulo: str
concluida: bool = field(default=False, compare=False)
etiquetas: list[str] = field(
default_factory=list,
repr=False,
compare=False,
)
def __post_init__(self) -> None:
self.titulo = self.titulo.strip()
if not self.titulo:
raise ValueError("O título não pode ficar vazio.")
if self.prioridade < 0:
raise ValueError("A prioridade não pode ser negativa.")
@dataclass(frozen=True)
class ChaveTarefa:
prioridade: int
titulo: str
# Padrão simples, normalização e representação.
primeira = Tarefa(2, " Estudar dataclasses ")
assert primeira.titulo == "Estudar dataclasses"
assert primeira.concluida is False
assert repr(primeira) == (
"Tarefa(prioridade=2, titulo='Estudar dataclasses', concluida=False)"
)
# Cada chamada sem etiquetas cria uma lista independente.
segunda = Tarefa(1, "Enviar relatório")
primeira.etiquetas.append("python")
assert primeira.etiquetas == ["python"]
assert segunda.etiquetas == []
# Prioridade e título definem igualdade e os desempates da ordem.
mesmos_dados = Tarefa(2, "Estudar dataclasses", etiquetas=["urgente"])
assert primeira == mesmos_dados
ordenadas = sorted([
Tarefa(2, "Zerar caixa de entrada"),
Tarefa(1, "Enviar relatório"),
Tarefa(2, "Aprender testes"),
])
assert [t.titulo for t in ordenadas] == [
"Enviar relatório",
"Aprender testes",
"Zerar caixa de entrada",
]
# A validação ocorre na construção.
try:
Tarefa(-1, "Inválida")
except ValueError as erro:
assert str(erro) == "A prioridade não pode ser negativa."
else:
raise AssertionError("Era esperado ValueError")
# Tarefa é mutável e, com eq=True, não é hashável.
primeira.concluida = True
try:
hash(primeira)
except TypeError:
pass
else:
raise AssertionError("Tarefa não deveria ser hashável")
# A chave congelada, feita apenas de valores hasháveis, pode ir para um conjunto.
chaves = {
ChaveTarefa(1, "Enviar relatório"),
ChaveTarefa(1, "Enviar relatório"),
ChaveTarefa(2, "Estudar dataclasses"),
}
assert len(chaves) == 2
print("Verificações concluídas.")Depois de executar o script, relate: qual comportamento comprovou que as etiquetas são independentes; quais campos decidiram a igualdade e a ordem; e por que Tarefa falha em hash(), mas ChaveTarefa entra no conjunto.
Escreva pelo menos 180 caracteres (0/180).
Resumo
field(default_factory=...).__post_init__ para normalizar e validar na construção; alterações posteriores exigem outra estratégia de controle.repr, igualdade e ordenação: essas decisões são independentes.Parabéns! Você concluiu: Modelar objetos de dados com dataclasses
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks