Argparse em Python: Guia Completo com Exemplos Práticos

Aprenda a usar o argparse em Python: argumentos posicionais e opcionais, flags, subcomandos, tipos, nargs, validação e boas práticas. Guia completo com exemplos.

8 min de leitura Equipe Python Brasil

O argparse é o módulo da biblioteca padrão do Python dedicado a criar interfaces de linha de comando (CLI). Com ele, você transforma um script simples em uma ferramenta profissional que aceita argumentos posicionais, flags, subcomandos, valida entradas e gera mensagens de ajuda automáticas — tudo sem instalar nenhuma dependência extra. Se você está começando agora, vale ler primeiro o Como Começar com Python; aqui o foco é colocar a mão na massa no terminal.

Para quem só quer uma definição rápida, temos a entrada de argparse no glossário. Neste guia completo, vamos do primeiro exemplo a subcomandos, validação customizada e boas práticas. Se o objetivo é comparar bibliotecas de CLI inteiras (argparse, Typer, Click e uv), confira o guia de CLI com Python — aqui mergulhamos fundo só no argparse, que é a base de todas elas.

Por que usar o argparse

Antes do argparse, muitos scripts Python lidavam com argumentos lendo sys.argv manualmente — frágil, repetitivo e propenso a erros. O argparse resolve três problemas de uma vez:

  1. Define o que o programa aceita: argumentos posicionais, flags, tipos e valores permitidos.
  2. Gera ajuda e uso automaticamente: o --help sai de graça, sempre atualizado.
  3. Valida e converte entradas: erros de tipo ou valor viram mensagens claras, não exceções obscuras.

Como faz parte da biblioteca padrão, o argparse está disponível em qualquer instalação de Python a partir da versão 3.2 — não há nada para instalar com gerenciadores de pacotes como o uv. É só importar e usar.

Primeiro exemplo: uma CLI em 10 linhas

Vamos criar uma ferramenta que processa um arquivo de texto e aceita um formato de saída. Salve como processa.py:

import argparse

parser = argparse.ArgumentParser(
    description="Processa um arquivo de texto e imprime o resultado.",
)

# Argumento posicional (obrigatório)
parser.add_argument("arquivo", help="Caminho do arquivo de entrada")

# Argumento opcional (flag com valor padrão)
parser.add_argument(
    "-f", "--formato",
    choices=["txt", "csv", "json"],
    default="txt",
    help="Formato de saída (padrão: txt)",
)

# Flag booleana
parser.add_argument("-v", "--verbose", action="store_true", help="Modo detalhado")

args = parser.parse_args()

print(f"Arquivo: {args.arquivo}")
print(f"Formato: {args.formato}")
print(f"Verbose: {args.verbose}")

Rode python processa.py dados.txt --formato csv -v e verá:

Arquivo: dados.txt
Formato: csv
Verbose: True

Experimente python processa.py -h. O argparse monta a ajuda sozinho, listando o argumento arquivo, a flag --formato (com as opções aceitas) e a flag --verbose. É difícil exagerar o quanto isso economiza tempo quando a CLI cresce.

Argumentos posicionais e opcionais

A diferença entre os dois é o prefixo do nome:

  • Posicional ("arquivo"): obrigatório, definido pela ordem em que aparece. Bom para a entrada principal do comando.
  • Opcional ("-f", "--formato"): começa com - (curto) ou -- (longo). Pode ter valor padrão e geralmente não é obrigatório.
parser.add_argument("origem", help="Arquivo de origem")        # posicional
parser.add_argument("-o", "--saida", help="Arquivo de saída")   # opcional

Se um argumento posicional faltar, o argparse encerra com erro e mostra o uso — você não precisa escrever essa lógica.

Tipos, valores permitidos e defaults

O parâmetro type converte a entrada; choices restringe os valores; default define o valor quando o argumento não aparece:

parser.add_argument("--porta", type=int, default=8000, help="Porta do servidor")
parser.add_argument("--nivel", choices=["debug", "info", "erro"], default="info")
parser.add_argument("--taxa", type=float, default=0.5, help="Taxa de processamento")

Assim, --porta abc vira um erro claro em vez de um int() quebrado no meio da execução. Para datas e outros formatos, basta passar uma função que faça a conversão (veremos isso na seção de validação).

Flags booleanas e a armadilha do type=bool

Para ligar/desligar um comportamento, use action:

parser.add_argument("--verbose", action="store_true", help="Liga o modo detalhado")
parser.add_argument("--silencioso", action="store_false", dest="verbose")
  • action="store_true"False por padrão, True quando a flag aparece.
  • action="store_false" → o oposto (útil para uma flag --nao-verbose).
  • action="count" → conta repetições (-vvv vira 3), ótimo para níveis de verbosidade.
  • action="append" → acumula valores repetidos em uma lista (--tag a --tag b["a", "b"]).

Armadilha clássica: type=bool não funciona. --ativo=False ainda vira True, porque bool("False") é True (string não vazia). Para booleanos, sempre use action.

Aceitando múltiplos valores com nargs

O nargs controla quantos valores um argumento consome:

parser.add_argument("--arquivos", nargs="+", help="Um ou mais arquivos")
parser.add_argument("--dimensoes", nargs=2, type=int, metavar=("LARGURA", "ALTURA"))
parser.add_argument("--log", nargs="?", const="app.log", default=None,
                    help="Sem valor usa app.log; ausente fica None")
  • nargs="+" → um ou mais valores (lista).
  • nargs="*" → zero ou mais (lista, pode ser vazia).
  • nargs="?" → valor opcional; const é usado quando a flag aparece sem valor.
  • nargs=2 → exatamente dois valores.

O resultado chega sempre como lista quando nargs é +, * ou um número.

Subcomandos com add_subparsers

Ferramentas como git usam subcomandos (git commit, git push). O argparse faz isso com add_subparsers:

import argparse

parser = argparse.ArgumentParser(prog="dbcli", description="Gerencia um banco de dados")
sub = parser.add_subparsers(dest="comando", required=True, help="Comandos disponíveis")

# subcomando: criar
p_criar = sub.add_parser("criar", help="Cria um novo banco")
p_criar.add_argument("nome", help="Nome do banco")
p_criar.add_argument("--tipo", choices=["sqlite", "postgres"], default="sqlite")

# subcomando: backup
p_backup = sub.add_parser("backup", help="Faz backup do banco")
p_backup.add_argument("destino", help="Diretório de destino")
p_backup.add_argument("--compactar", action="store_true")

args = parser.parse_args()

if args.comando == "criar":
    print(f"Criando banco {args.nome} ({args.tipo})")
elif args.comando == "backup":
    print(f"Backup para {args.destino} (compactar={args.compactar})")

Agora python dbcli.py criar loja --tipo postgres e python dbcli.py backup /tmp funcionam como comandos separados, cada um com a própria ajuda. O padrão set_defaults(func=...) é uma forma elegante de despachar para a função certa sem uma cadeia de if.

Mensagens de ajuda personalizadas

Quatro parâmetros deixam a ajuda profissional:

parser = argparse.ArgumentParser(
    prog="logtools",
    description="Analisa arquivos de log de aplicação.",
    epilog="Exemplo: logtools analisar app.log --nivel erro",
    formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("--version", action="version", version="%(prog)s 1.0.0")
  • prog → nome do programa na ajuda (útil quando o nome do arquivo não é o que o usuário digita).
  • description e epilog → texto no topo e no rodapé da ajuda.
  • formatter_class=argparse.RawDescriptionHelpFormatter → preserva quebras de linha no epilog (caso você queira listar exemplos).
  • action="version" → imprime a versão e sai.

Grupos mutuamente exclusivos e organização

Para flags que não fazem sentido juntas (--json ou --csv, nunca ambos):

grupo = parser.add_mutually_exclusive_group()
grupo.add_argument("--json", action="store_true", help="Saída em JSON")
grupo.add_argument("--csv", action="store_true", help="Saída em CSV")

E para organizar a ajuda em seções lógicas, use add_argument_group:

srv = parser.add_argument_group("opções do servidor")
srv.add_argument("--host", default="localhost")
srv.add_argument("--porta", type=int, default=8000)

Validação customizada com type

O type aceita qualquer função que receba uma string e devolva o valor convertido — ou levante argparse.ArgumentTypeError. Isso centraliza a validação:

import argparse
from pathlib import Path

def arquivo_existente(caminho: str) -> Path:
    p = Path(caminho)
    if not p.is_file():
        raise argparse.ArgumentTypeError(f"Arquivo não encontrado: {caminho}")
    return p

def porta_valida(valor: str) -> int:
    porta = int(valor)
    if not (1 <= porta <= 65535):
        raise argparse.ArgumentTypeError("A porta deve estar entre 1 e 65535")
    return porta

parser = argparse.ArgumentParser()
parser.add_argument("entrada", type=arquivo_existente)
parser.add_argument("--porta", type=porta_valida, default=8000)

args = parser.parse_args()
print(f"Lendo: {args.entrada} | porta: {args.porta}")

A mensagem de erro aparece formatada como uso incorreto, mantendo a CLI consistente. Combinado com type hints, o código fica legível e seguro.

Erros comuns

  • Confundir posicional com opcional: esquecer o -- transforma uma flag em obrigatório e quebra o uso.
  • type=bool: não use para flags; prefira action="store_true"/"store_false".
  • nargs="*" vazio: aceita zero valores e devolve uma lista vazia — trate esse caso antes de iterar.
  • Subcomando ausente: sem required=True (ou dest) em add_subparsers, o atributo pode não existir e causa AttributeError. Defina dest e valide antes de acessar.
  • Ajuda genérica: strings de help vagas tornam a CLI difícil. Descreva o que cada argumento faz e o valor padrão.

Boas práticas

  • Sempre passe description no parser e help em cada argumento.
  • Use choices para restringir valores e evitar validação manual.
  • Centralize conversões complexas em funções de type reutilizáveis.
  • Adicione --version e um --verbose como padrão em ferramentas sérias.
  • Quebre CLIs grandes em subcomandos em vez de uma única lista longa de flags.
  • Escreva exemplos no epilog — usuários copiam exemplos muito mais do que leem a ajuda inteira.

Para ferramentas que vão crescer muito, vale considerar Typer ou Click, mas entender o argparse primeiro torna qualquer migração trivial, porque os conceitos (argumentos, flags, subcomandos, ajuda) são os mesmos.

Testando uma CLI de argparse

CLIs merecem testes. O truque é chamar parse_args passando uma lista de argumentos, sem depender do sys.argv real:

def test_formato_padrao():
    args = parser.parse_args(["dados.txt"])
    assert args.formato == "txt"
    assert args.verbose is False

def test_flag_verbose():
    args = parser.parse_args(["dados.txt", "-v"])
    assert args.verbose is True

Esse padrão roda direto com pytest e deixa a CLI segura para refatorar. Se você usa Ruff para lint e formatação, a integração com testes é imediata.

Perguntas frequentes

O argparse exige instalação?

Não. O argparse faz parte da biblioteca padrão do Python desde a versão 3.2, então basta import argparse — não é preciso pip install nem nada do uv.

Como fazer --formato aceitar só alguns valores?

Use choices: parser.add_argument("--formato", choices=["txt", "csv", "json"], default="txt"). Qualquer valor fora da lista vira erro automático com mensagem de uso.

Argparse conta como projeto de portfólio?

Sim. Uma CLI pequena com testes, README, tratamento de erro e exemplos mostra automação prática e maturidade — ótimo para um portfólio Python e para processos de vagas. Combine com subcomandos e validação e ela se destaca mais que um script solto.

Próximos passos

Você agora tem o argparse suficiente para construir CLIs profissionais sem dependências. Para evoluir:

Dominar o argparse é um desses fundamentos que aparecem em quase toda vaga Python — vale o investimento.

E

Equipe Python Brasil

Contribuidor do Python Brasil — Aprenda Python em Português