dataclass_transform no Python: classes geradas

Publicado em: 29/08/2026
Tempo de leitura: 6 minutos
A laptop screen showing a code editor with visible programming code in a dimly lit environment.

typing.dataclass_transform permite que uma biblioteca informe ao analisador estático que um decorator, uma classe base ou uma metaclass cria comportamento semelhante ao de @dataclass. Frameworks que geram __init__, campos, comparação, ordenação ou modelos declarativos podem oferecer uma experiência de tipagem precisa sem exigir que o usuário aplique o decorator padrão de dataclasses.

O recurso não transforma classes por conta própria. Ele é um marcador para ferramentas estáticas. A biblioteca continua responsável por implementar o comportamento em runtime. Neste guia, você aprenderá a declarar transforms, criar decorators e bases, definir defaults, field specifiers, aliases, campos keyword-only, frozen, herança e testes.

O problema de classes geradas

def modelo(cls):
    # gera __init__ dinamicamente
    return cls

@modelo
class Usuario:
    nome: str
    idade: int

usuario = Usuario(nome="Ana", idade=30)

Em runtime, o framework pode adicionar um construtor. Sem informação adicional, o analisador enxerga uma classe sem __init__ compatível e sinaliza a chamada como inválida.

Marcando o decorator

from typing import dataclass_transform

@dataclass_transform()
def modelo(cls):
    return transformar_em_modelo(cls)

Agora o analisador trata classes decoradas por @modelo como dataclass-like. Ele pode sintetizar o construtor com base nas anotações dos campos.

Runtime continua sendo responsabilidade da biblioteca

dataclass_transform não cria métodos. Se transformar_em_modelo() não gerar o __init__, o código falha em execução mesmo que o analisador aceite. O contrato estático e a implementação precisam permanecer alinhados.

Decorator tipado

from typing import TypeVar

T = TypeVar("T", bound=type)

@dataclass_transform()
def modelo(cls: T) -> T:
    return transformar_em_modelo(cls)

O decorator devolve a mesma classe em termos estáticos. Para APIs mais complexas, use parâmetros genéricos adequados e preserve metadados de runtime.

Classe base transformadora

@dataclass_transform()
class ModeloBase:
    pass

class Produto(ModeloBase):
    id: int
    nome: str

produto = Produto(id=1, nome="Teclado")

Todas as subclasses são tratadas como dataclass-like. Esse padrão é comum em ORMs, bibliotecas de validação e modelos de configuração.

Metaclass transformadora

@dataclass_transform()
class ModeloMeta(type):
    ...

class Modelo(metaclass=ModeloMeta):
    ...

Uma metaclass pode coletar anotações, gerar métodos e registrar campos. O marcador informa ao analisador sobre esse comportamento.

eq_default

@dataclass_transform(eq_default=True)
def modelo(cls):
    ...

eq_default informa se igualdade é gerada por padrão quando o usuário não especifica outra opção. Isso afeta a forma como ferramentas modelam métodos sintetizados.

order_default

@dataclass_transform(order_default=False)
def modelo(cls):
    ...

O parâmetro descreve se métodos de ordenação são criados por padrão. A biblioteca deve oferecer comportamento correspondente em runtime.

kw_only_default

@dataclass_transform(kw_only_default=True)
class ModeloBase:
    ...

Campos são tratados como keyword-only por padrão:

class Usuario(ModeloBase):
    nome: str
    idade: int

Usuario(nome="Ana", idade=30)
# Usuario("Ana", 30) deve ser rejeitado

frozen_default

Versões modernas permitem indicar se modelos são congelados por padrão. Isso influencia atribuições estáticas e relações de herança. A implementação precisa impedir mutação em runtime se promete frozen.

Field specifiers

Frameworks geralmente fornecem uma função de campo:

def campo(*, default=..., alias: str | None = None):
    ...

Informe ao analisador que essa função possui semântica semelhante a dataclasses.field():

@dataclass_transform(field_specifiers=(campo,))
def modelo(cls):
    ...

O checker pode interpretar defaults, factories, aliases, init e opções keyword-only conforme a assinatura do specifier.

Default e default_factory

class Carrinho(ModeloBase):
    itens: list[str] = campo(default_factory=list)
    aberto: bool = campo(default=True)

A biblioteca precisa evitar defaults mutáveis compartilhados e executar factories por instância, assim como dataclasses.

Campos fora do __init__

class Registro(ModeloBase):
    id: int = campo(init=False)
    nome: str

O analisador deve omitir id do construtor se o field specifier comunica init=False. O runtime deve preencher o campo por outro mecanismo.

Aliases de parâmetros

class Usuario(ModeloBase):
    nome_completo: str = campo(alias="nome")

Alguns frameworks aceitam Usuario(nome="Ana") embora o atributo seja nome_completo. Field specifiers podem comunicar aliases ao analisador quando o recurso é suportado.

Ordem de campos

Campos sem default geralmente devem aparecer antes de campos com default no construtor posicional. Bibliotecas que oferecem keyword-only podem flexibilizar a regra. Mantenha o comportamento estático igual ao runtime.

Herança

class Entidade(ModeloBase):
    id: int

class Usuario(Entidade):
    nome: str

O analisador combina campos da base e da derivada. A ordem, defaults e frozen precisam respeitar as regras declaradas pelo framework.

Override de campos

Redefinir um campo em uma subclasse pode mudar tipo, default ou opções. O framework deve definir políticas claras. Mudanças incompatíveis podem quebrar substituição e construtores.

Classes congeladas e herança

Modelos frozen e não frozen possuem restrições de herança semelhantes às dataclasses. Não prometa imutabilidade estática e permita mutação silenciosa no runtime. Teste atribuições e construção em todas as combinações suportadas.

Decorators com argumentos

@dataclass_transform()
def modelo(*, frozen: bool = False, kw_only: bool = False):
    def aplicar(cls):
        return transformar(cls, frozen=frozen, kw_only=kw_only)
    return aplicar

@modelo(frozen=True)
class Configuracao:
    host: str

Para o analisador entender flags, nomes e valores precisam seguir convenções reconhecidas. Use Literal[True] quando necessário para opções que afetam o tipo.

Assinaturas sobrecarregadas do decorator

Decorators que aceitam uso com e sem parênteses podem precisar de overloads:

@modelo
class A: ...

@modelo(frozen=True)
class B: ...

Escreva uma API clara e teste as duas formas. A complexidade do decorator pode tornar as anotações difíceis; simplifique quando possível.

Comparação com @dataclass

Use @dataclass diretamente quando ele atende às necessidades. dataclass_transform é destinado a autores de frameworks que oferecem uma semântica própria, como validação, ORM, conversão, descriptors ou registro de campos.

Comparação com Protocol

Protocol descreve capacidades que um objeto já possui. dataclass_transform ensina ao analisador que uma ferramenta gera métodos e construtores. Os recursos podem coexistir, mas resolvem problemas diferentes.

Introspecção

O marcador pode deixar metadados como __dataclass_transform__ para ferramentas. Não confunda isso com dataclasses.is_dataclass(). Uma classe transformada por framework pode não ser uma dataclass real.

Geradores de schema

O framework deve manter sua própria representação de campos, defaults e validação. dataclass_transform melhora a experiência estática, mas não fornece APIs de serialização, schema ou reflexão.

Testes estáticos

from typing import assert_type

usuario = Usuario(nome="Ana", idade=30)
assert_type(usuario.nome, str)
assert_type(usuario.idade, int)

Adicione casos que devem falhar: campo ausente, nome extra, tipo errado, argumento posicional proibido e mutação de frozen.

Testes de runtime

Execute a mesma matriz de casos em runtime. Uma divergência é perigosa: o analisador pode aceitar algo que falha ou rejeitar uma chamada válida. Teste assinaturas com inspect.signature(), criação, defaults, factories, igualdade e herança.

Compatibilidade de analisadores

Mypy e pyright podem implementar detalhes em ritmos diferentes. Consulte a especificação, evite extensões não portáveis e execute uma suíte nos analisadores suportados.

Compatibilidade de versões

Use typing_extensions.dataclass_transform em versões anteriores. O decorator pode ser importado da extensão sem alterar o comportamento de runtime da biblioteca.

Erros comuns

  • Achar que o marcador gera métodos: a biblioteca ainda precisa implementá-los.
  • Prometer defaults diferentes do runtime: o construtor fica divergente.
  • Esquecer field_specifiers: o analisador não entende sua função de campo.
  • Não testar herança: ordem e frozen podem quebrar.
  • Criar decorator excessivamente dinâmico: ferramentas não conseguem modelá-lo.
  • Usar quando @dataclass bastaria: aumenta manutenção sem benefício.

Exemplo completo: mini framework

from dataclasses import dataclass, field
from typing import dataclass_transform


def atributo(*, default=..., default_factory=...):
    if default_factory is not ...:
        return field(default_factory=default_factory)
    if default is not ...:
        return field(default=default)
    return field()

@dataclass_transform(field_specifiers=(atributo,))
def modelo(cls=None, *, frozen: bool = False):
    def aplicar(alvo):
        return dataclass(alvo, frozen=frozen)
    if cls is None:
        return aplicar
    return aplicar(cls)

@modelo(frozen=True)
class Produto:
    id: int
    nome: str
    tags: list[str] = atributo(default_factory=list)

produto = Produto(id=1, nome="Teclado")

O runtime delega à dataclass real; o marcador comunica a semântica do decorator customizado ao analisador. Frameworks reais podem adicionar validação, aliases e conversão.

Quando usar

Use dataclass_transform se você é autor de uma biblioteca que gera construtores e campos a partir de anotações. Usuários comuns raramente precisam aplicá-lo diretamente. Para modelos de aplicação, dataclass, attrs, Pydantic ou classes normais geralmente são suficientes.

Conclusão

dataclass_transform cria uma ponte entre frameworks declarativos e analisadores estáticos. Ele descreve métodos e parâmetros sintetizados, defaults, fields, keyword-only e frozen sem impor uma implementação específica.

A documentação oficial de dataclass_transform no módulo typing detalha os parâmetros. Mantenha a implementação de runtime alinhada ao contrato, declare field specifiers e proteja a experiência do usuário com testes estáticos e de execução.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    High-angle view of woman coding on a laptop, with a Python book nearby. Ideal for programming and tech content.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    TypeVarTuple no Python: genéricos variádicos

    Aprenda TypeVarTuple no Python para preservar tuplas heterogêneas, modelar dimensões e criar genéricos com vários parâmetros.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026
    Close-up of a laptop screen with code and a coffee mug, perfect for tech abstract themes.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    assert_type e reveal_type: teste inferência de tipos

    Aprenda assert_type e reveal_type no Python para inspecionar inferência, testar APIs tipadas e evitar regressões no analisador.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026
    Close-up image of a woman's hand holding a stack of spiral-bound notebooks and papers against a dark background.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    get_type_hints no Python: leia anotações

    Aprenda get_type_hints no Python para resolver referências futuras, ler Annotated e inspecionar funções e classes com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026
    A laptop screen showing a code editor with visible programming code in a dimly lit environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    runtime_checkable no Python: Protocol em runtime

    Aprenda runtime_checkable no Python para testar Protocol com isinstance, entender limites e criar contratos estruturais seguros.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026
    Close-up of a laptop screen with code and a coffee mug, perfect for tech abstract themes.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    Unpack no Python: kwargs e tipos variádicos

    Aprenda typing.Unpack no Python para tipar **kwargs com TypedDict, expandir tuplas variádicas e preservar assinaturas precisas.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026
    High-angle view of woman coding on a laptop, with a Python book nearby. Ideal for programming and tech content.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    Required e NotRequired: campos opcionais no TypedDict

    Aprenda Required e NotRequired no Python para controlar chaves obrigatórias e opcionais em TypedDict com contratos claros.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026