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.
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:
- Define o que o programa aceita: argumentos posicionais, flags, tipos e valores permitidos.
- Gera ajuda e uso automaticamente: o
--helpsai de graça, sempre atualizado. - 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"→Falsepor padrão,Truequando a flag aparece.action="store_false"→ o oposto (útil para uma flag--nao-verbose).action="count"→ conta repetições (-vvvvira3), ó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).descriptioneepilog→ texto no topo e no rodapé da ajuda.formatter_class=argparse.RawDescriptionHelpFormatter→ preserva quebras de linha noepilog(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; prefiraaction="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(oudest) emadd_subparsers, o atributo pode não existir e causaAttributeError. Definadeste valide antes de acessar. - Ajuda genérica: strings de
helpvagas tornam a CLI difícil. Descreva o que cada argumento faz e o valor padrão.
Boas práticas
- Sempre passe
descriptionno parser ehelpem cada argumento. - Use
choicespara restringir valores e evitar validação manual. - Centralize conversões complexas em funções de
typereutilizáveis. - Adicione
--versione um--verbosecomo 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:
- Compare com Typer e Click no guia de CLI com Python.
- Aprofunde tipagem com o guia de mypy e tipagem estática.
- Trate dados de entrada com expressões regulares e funções de validação.
Dominar o argparse é um desses fundamentos que aparecem em quase toda vaga Python — vale o investimento.
Equipe Python Brasil
Contribuidor do Python Brasil — Aprenda Python em Português