dataclasses.KW_ONLY: exija argumentos nomeados

Publicado em: 08/09/2026
Tempo de leitura: 5 minutos
Desenvolvedor criando modelos com dataclasses.KW_ONLY no Python

O recurso dataclasses.KW_ONLY permite definir, em uma dataclass, um ponto a partir do qual os campos só podem ser informados por nome. Isso torna construtores mais claros, reduz chamadas ambíguas e facilita a evolução de APIs sem quebrar código existente. Em vez de depender de uma longa sequência de argumentos posicionais, você pode exigir que parâmetros opcionais ou sensíveis sejam escritos explicitamente.

Neste guia, você vai entender como KW_ONLY funciona, quando ele é melhor que kw_only=True, como ele interage com herança, valores padrão, __match_args__ e dataclasses.replace, além de conhecer erros comuns e padrões úteis para código de produção.

O problema dos argumentos posicionais

Considere uma classe de configuração com vários campos booleanos e números. Uma chamada como Config('prod', True, False, 30) é difícil de ler. Quem revisa o código precisa consultar a assinatura para descobrir o significado de cada valor. Pior: trocar dois argumentos do mesmo tipo pode não gerar erro, mas alterar completamente o comportamento.

Com campos somente por palavra-chave, a chamada fica explícita: Config('prod', debug=True, cache=False, timeout=30). O código comunica intenção, e mudanças futuras na ordem dos campos têm menos chance de causar regressões silenciosas.

Como usar dataclasses.KW_ONLY

KW_ONLY é um marcador de tipo. Você declara um campo fictício, normalmente chamado _, e todos os campos definidos depois dele passam a ser keyword-only.

from dataclasses import dataclass, KW_ONLY

@dataclass
class Servico:
    nome: str
    _: KW_ONLY
    timeout: int = 30
    retries: int = 3
    debug: bool = False

api = Servico('pagamentos', timeout=10, retries=5)

O campo marcador não aparece como atributo da instância, não entra na representação e não precisa receber valor. Seu papel é apenas separar os campos posicionais dos campos nomeados.

Tentar chamar Servico('pagamentos', 10, 5) gera TypeError, pois timeout e retries devem ser fornecidos pelo nome.

KW_ONLY versus kw_only=True

A opção @dataclass(kw_only=True) torna todos os campos da classe somente por palavra-chave. É adequada quando nenhum argumento posicional faz sentido. Já KW_ONLY é mais seletivo: mantém alguns campos essenciais como posicionais e exige nomes apenas para os demais.

Uma regra prática é deixar posicionais somente os campos que identificam claramente o objeto e dificilmente mudarão. Configurações, flags, limites, políticas e opções futuras costumam ser melhores como keyword-only.

Valores padrão e clareza da assinatura

Campos após o marcador podem ter ou não valor padrão. Um campo obrigatório continua obrigatório, mas precisa ser nomeado.

@dataclass
class Conexao:
    host: str
    _: KW_ONLY
    token: str
    porta: int = 443
    verificar_tls: bool = True

c = Conexao('api.exemplo.com', token='segredo')

Esse padrão é especialmente útil para credenciais e parâmetros de segurança. A presença explícita de token= ou verificar_tls= reduz erros em chamadas extensas.

Herança e ordem dos campos

Dataclasses combinam campos das classes base e derivadas. Por isso, a ordem final da assinatura deve ser verificada quando há herança. Um marcador na classe base afeta a definição daquela classe, mas uma subclasse pode adicionar novos campos e regras próprias. Teste a assinatura pública com inspect.signature para garantir que o construtor final esteja como esperado.

from inspect import signature
print(signature(Servico))

Em bibliotecas, vale incluir esse teste para evitar que uma refatoração altere acidentalmente quais parâmetros são posicionais.

Pattern matching e __match_args__

Campos keyword-only não são incluídos em __match_args__. Isso significa que o pattern matching posicional considera apenas os campos posicionais. Esse comportamento é positivo porque mantém padrões estruturais mais estáveis.

match api:
    case Servico(nome):
        print(nome)

Para testar campos nomeados, use padrões por atributo: case Servico(timeout=10). Essa forma é mais explícita e continua funcionando mesmo quando a ordem interna muda.

dataclasses.replace e cópias seguras

dataclasses.replace trabalha naturalmente com campos keyword-only, pois as alterações são passadas por nome. Isso combina bem com modelos imutáveis criados com frozen=True.

from dataclasses import replace
rapido = replace(api, timeout=5)

O resultado é uma nova instância com o campo modificado, preservando os demais valores e mantendo a legibilidade.

Quando usar em APIs públicas

Em uma API pública, argumentos posicionais fazem parte do contrato. Inserir um novo parâmetro no meio da assinatura pode quebrar chamadas antigas. Com keyword-only, novos campos opcionais podem ser adicionados com muito menos risco, desde que tenham valores padrão adequados.

Esse benefício é importante em SDKs, bibliotecas internas, modelos de configuração, objetos de domínio e serviços que mudam ao longo do tempo. O recurso não elimina a necessidade de versionamento, mas reduz a superfície de incompatibilidade.

Erros comuns

O primeiro erro é usar vários marcadores KW_ONLY na mesma dataclass. Apenas um é necessário. O segundo é escolher um nome relevante para o marcador; use _ para deixar claro que não é um campo real. O terceiro é tornar keyword-only um identificador que todos esperam passar posicionalmente, criando uma API excessivamente verbosa.

Outro erro é confiar apenas na dataclass para validação. KW_ONLY controla a forma da chamada, mas não valida conteúdo. Use __post_init__ para regras como timeout positivo, limites de tentativas ou combinações inválidas.

Exemplo com validação

@dataclass
class Job:
    nome: str
    _: KW_ONLY
    prioridade: int = 5
    tentativas: int = 3

    def __post_init__(self):
        if not 1 <= self.prioridade <= 10:
            raise ValueError('prioridade deve estar entre 1 e 10')
        if self.tentativas < 0:
            raise ValueError('tentativas não pode ser negativo')

A assinatura fica clara e a validação protege o estado. As duas técnicas resolvem problemas diferentes e se complementam.

Boas práticas

Mantenha poucos campos posicionais, normalmente um ou dois. Use nomes descritivos para opções. Forneça padrões seguros. Documente campos obrigatórios. Teste a assinatura e as mensagens de erro. Em modelos grandes, considere separar configurações em dataclasses menores em vez de criar um construtor com dezenas de parâmetros.

Também compare com outras ferramentas. Para dados validados externamente, bibliotecas como Pydantic podem ser mais apropriadas. Para estruturas simples e tipadas, dataclasses continuam leves e integradas à biblioteca padrão.

Leituras relacionadas

Veja também nossos guias sobre typing.override no Python, StrEnum no Python, SimpleNamespace no Python e types.new_class no Python. Eles ajudam a projetar modelos, contratos e APIs mais previsíveis.

Consulte ainda a documentação oficial de dataclasses e a PEP 557, que descreve a motivação e o design das dataclasses.

Conclusão

dataclasses.KW_ONLY é um recurso pequeno com grande impacto na legibilidade e estabilidade de APIs. Ele permite preservar argumentos posicionais realmente essenciais e exigir nomes para opções que poderiam ser confundidas. Em projetos que evoluem continuamente, essa separação reduz erros, melhora revisões de código e facilita a inclusão de novos campos. Use-o principalmente em configurações, flags e parâmetros opcionais, combinado com validação, testes de assinatura e documentação clara.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Desenvolvedor usando operator.methodcaller em código Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    operator.methodcaller: chame métodos em pipelines

    Aprenda operator.methodcaller no Python para chamar métodos em map, sorted e pipelines com argumentos e código mais declarativo.

    Ler mais

    Tempo de leitura: 5 minutos
    07/09/2026
    Estrutura de pastas percorrida com pathlib.Path.walk no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pathlib.Path.walk: percorra e filtre diretórios

    Aprenda a percorrer diretórios com pathlib.Path.walk no Python, filtrar arquivos, ignorar pastas e evitar armadilhas comuns.

    Ler mais

    Tempo de leitura: 5 minutos
    07/09/2026
    Código Python validado com enum.verify
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    enum.verify: valide regras de Enum no Python

    Aprenda enum.verify no Python para validar valores únicos, sequências contínuas e flags nomeadas com regras explícitas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/09/2026
    Grafo de dependências e fluxo de tarefas com TopologicalSorter no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    TopologicalSorter: ordene dependências sem ciclos

    Aprenda TopologicalSorter no Python para ordenar dependências, detectar ciclos e executar pipelines sequenciais ou paralelos com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    06/09/2026
    Pastas e diretórios representando os.fwalk no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    os.fwalk no Python: percorra diretórios

    Aprenda os.fwalk no Python para percorrer diretórios com descritores, reduzir condições de corrida e manipular arquivos com mais segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    05/09/2026
    Desenvolvedor revisando código Python e métodos sobrescritos
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    typing.override: valide sobrescritas de métodos

    Aprenda typing.override no Python para validar sobrescritas, assinaturas, refatorações e contratos de herança com análise estática.

    Ler mais

    Tempo de leitura: 5 minutos
    05/09/2026