Python argparse
Até aqui, quando um programa precisava de uma informação, ele perguntava com input() e esperava a pessoa digitar. Os programas do terminal costumam funcionar de outro jeito: você já diz tudo na hora de chamar, na mesma linha. ls -a, pip install requests, python3 -m venv .venv: as palavras depois do nome do programa são os argumentos. Nesta aula você vai fazer os seus programas receberem argumentos, primeiro do jeito mais cru (sys.argv) e depois do jeito certo, com o módulo argparse ("analisador de argumentos"), que ainda escreve a ajuda e as mensagens de erro para você.
- O que são argumentos de linha de comando, e como o Python os entrega em
sys.argv. - Por que
sys.argvsozinho dá trabalho (oIndexError, tudo vem como texto). - A montar um programa com
argparse:ArgumentParser,add_argument,parse_args. - A diferença entre argumentos posicionais (obrigatórios) e opcionais (
-q,--quantidade). - As opções mais usadas:
help,type=int,default,choices,action="store_true",nargs="+". - A ler o
--helpque oargparsegera e as mensagens de erro reais dele.
A ideia: o pedido já vem completo
Na padaria da Ana, tem cliente que chega e espera ela perguntar: "Qual bolo? Quantos? É para entregar?". Isso é o input(): o programa pergunta, a pessoa responde, uma coisa de cada vez. E tem cliente que já chega com o bilhete pronto: "Bia, cenoura, 3, entregar". A Ana lê o bilhete e pronto, sem conversa.
Os argumentos de linha de comando são esse bilhete. Quem chama o programa escreve tudo junto:
python3 encomenda.py Bia cenoura --quantidade 3 --entrega
Isso tem uma grande vantagem: o programa pode ser chamado por outros programas, por um agendador, por um script, sem ninguém sentado na frente para responder perguntas. E o comando inteiro pode ser repetido com a seta para cima do terminal.
| Peça | Exemplo | O que é |
|---|---|---|
| O programa | python3 encomenda.py | O Python e o arquivo que ele vai rodar |
| Argumento posicional | Bia, cenoura | Vale pela posição: o primeiro é o cliente, o segundo é o sabor |
| Opção com valor | --quantidade 3 | Um nome que começa com -- (ou -), seguido do valor |
| Opção liga/desliga | --entrega | Só o nome: estar ali já quer dizer "sim" |
1. Antes do argparse: sys.argv
O Python guarda os argumentos numa lista chamada argv (de argument vector, "lista de argumentos"), dentro do módulo sys. Para ver o que chega, um programa que só mostra a lista:
import sys
print("sys.argv =", sys.argv)
print("Quantos:", len(sys.argv))
$ python3 argumentos.py sys.argv = ['argumentos.py'] Quantos: 1 $ python3 argumentos.py bolo 3 sys.argv = ['argumentos.py', 'bolo', '3'] Quantos: 3 $ python3 argumentos.py "bolo de cenoura" 3 sys.argv = ['argumentos.py', 'bolo de cenoura', '3'] Quantos: 3
- sys.argv[0]
- Sempre o nome do programa:
'argumentos.py'. Os argumentos de verdade começam no índice 1. - 'bolo', '3'
- Cada palavra separada por espaço vira um item. Repare nas aspas: o
3chegou como o texto'3', não como número. - "bolo de cenoura"
- Entre aspas, no terminal, várias palavras viram um argumento só. As aspas são do terminal: não chegam ao Python.
Com isso já dá para fazer um programa que cumprimenta quem você disser:
import sys
nome = sys.argv[1]
print(f"Olá, {nome}!")
$ python3 ola.py Bia
Olá, Bia!
$ python3 ola.py
Traceback (most recent call last):
File "/home/ana/ola.py", line 3, in <module>
nome = sys.argv[1]
~~~~~~~~^^^
IndexError: list index out of range
Com o nome, funciona. Sem ele, o programa quebra: a lista só tinha o item 0, e o programa pediu o item 1. IndexError: list index out of range é "índice fora do intervalo da lista" (o mesmo erro da aula Acessando Itens). As marcas ~~~~~~~~^^^ apontam o pedaço culpado: o [1]. Para quem só queria usar o programa, essa mensagem não explica nada.
E o problema do texto:
import sys numero = sys.argv[1] print(numero * 2) print(int(numero) * 2)
$ python3 dobro.py 21 2121 42
'21' * 2 é o texto repetido duas vezes: 2121. Só depois do int() (aula Conversão de Tipos) é que vira a conta 42. Com sys.argv, toda conversão e toda conferência ficam por sua conta.
O editor do guia também passa argumentos para o programa: nesta caixa, é como se você tivesse digitado python3 main.py Bia 3.
Missão: a Bia pediu 3 pacotes de pão, e cada pacote tem 2 pães. O programa mostra Bia pediu 33 pães, porque o 3 chegou como texto. Conserte para mostrar Bia pediu 6 pães.
import sys
cliente = sys.argv[1]
pacotes = sys.argv[2]
print(f"{cliente} pediu {pacotes * 2} pães")
import sys
cliente = sys.argv[1]
pacotes = int(sys.argv[2])
print(f"{cliente} pediu {pacotes * 2} pães")
2. O primeiro programa com argparse
O argparse faz o trabalho chato: confere se veio tudo, converte os tipos, explica o erro e ainda escreve a ajuda. Ele vem com o Python (biblioteca padrão), não precisa instalar. O mesmo cumprimento:
import argparse
parser = argparse.ArgumentParser(description="Cumprimenta uma pessoa.")
parser.add_argument("nome")
args = parser.parse_args()
print(f"Olá, {args.nome}!")
- import argparse
- Traz o módulo.
- argparse.ArgumentParser(…)
- Cria o analisador (em inglês, parser): o "leitor do bilhete". Fica na variável
parser, o nome de costume. - description="…"
- Uma frase que explica o programa. Aparece na ajuda.
- parser.add_argument("nome")
- "Acrescente um argumento chamado
nome". Sem tracinho na frente, ele é posicional, e obrigatório. - args = parser.parse_args()
- "Analise os argumentos": lê o
sys.argv, confere tudo e devolve um objeto com um campo para cada argumento. Se algo estiver errado, o programa para aqui, com uma mensagem clara. - args.nome
- O valor que veio, pelo nome que você deu no
add_argument, com um ponto no meio.
$ python3 saudacao.py Bia Olá, Bia! $ python3 saudacao.py usage: saudacao.py [-h] nome saudacao.py: error: the following arguments are required: nome $ echo $? 2
Compare com o IndexError da seção anterior. Agora, sem o nome, o programa responde em duas linhas:
- usage: saudacao.py [-h] nome
- "Uso": como chamar o programa. Entre colchetes, o que é opcional (
-h); sem colchetes, o que é obrigatório (nome). - error: the following arguments are required: nome
- "Erro: os seguintes argumentos são obrigatórios:
nome". Diz exatamente o que faltou. - echo $?
- Mostra o código de saída do último programa. 0 é "deu certo"; o
argparsesai com 2, o costume do terminal para "você chamou errado".
O --help veio de graça
Você não escreveu nenhuma ajuda, mas o argparse criou a opção -h (ou --help, "ajuda") sozinho:
$ python3 saudacao.py --help usage: saudacao.py [-h] nome Cumprimenta uma pessoa. positional arguments: nome options: -h, --help show this help message and exit
- usage: …
- A mesma linha de uso do erro.
- Cumprimenta uma pessoa.
- A sua
description. - positional arguments:
- "Argumentos posicionais": a lista dos obrigatórios.
- options:
- "Opções": as que começam com tracinho.
- -h, --help show this help message and exit
- "Mostra esta mensagem de ajuda e sai". Os textos fixos do
argparsesão em inglês; os seus (a descrição, as ajudas de cada argumento) saem como você escrever.
Num terminal de verdade, o Python 3.14 pinta a ajuda e os erros do argparse: "usage" em azul, o nome do programa em roxo, as opções em verde. Quando a saída vai para um arquivo ou para outro programa, as cores somem sozinhas. Num Python mais antigo (como o 3.13 do Debian 13), o texto é o mesmo, sem cor.
3. Um programa de verdade: as encomendas da padaria
Agora o bilhete completo: o cliente e o sabor (obrigatórios), a quantidade (se não disser, é 1) e se é para entregar. Cada add_argument é uma linha do bilhete:
import argparse
parser = argparse.ArgumentParser(
description="Anota uma encomenda da padaria da Ana.",
)
parser.add_argument("cliente", help="nome de quem encomendou")
parser.add_argument("sabor", choices=["chocolate", "cenoura", "milho"], help="sabor do bolo")
parser.add_argument("-q", "--quantidade", type=int, default=1, help="quantos bolos (padrão: 1)")
parser.add_argument("-e", "--entrega", action="store_true", help="levar na casa do cliente")
args = parser.parse_args()
print(f"Cliente: {args.cliente}")
print(f"Bolo de {args.sabor} x {args.quantidade}")
if args.entrega:
print("Entregar em casa.")
else:
print("Retirar na padaria.")
| Parte | O que faz |
|---|---|
"cliente" | Posicional: o primeiro argumento sem tracinho |
help="…" | A explicação que aparece no --help |
choices=[…] | "Escolhas": só aceita um destes valores |
"-q", "--quantidade" | Opcional, com dois nomes: o curto (um tracinho, uma letra) e o longo (dois tracinhos, a palavra). O campo se chama pelo nome longo: args.quantidade |
type=int | Converte o texto para número inteiro (e reclama se não der) |
default=1 | O valor "padrão", quando a opção não aparece |
action="store_true" | "Guarde verdadeiro": a opção não recebe valor; se aparecer, args.entrega é True, se não, False |
A ajuda agora explica tudo isso sozinha:
$ python3 encomenda.py --help
usage: encomenda.py [-h] [-q QUANTIDADE] [-e]
cliente {chocolate,cenoura,milho}
Anota uma encomenda da padaria da Ana.
positional arguments:
cliente nome de quem encomendou
{chocolate,cenoura,milho}
sabor do bolo
options:
-h, --help show this help message and exit
-q, --quantidade QUANTIDADE
quantos bolos (padrão: 1)
-e, --entrega levar na casa do cliente
- [-q QUANTIDADE]
- Entre colchetes: opcional.
QUANTIDADEem maiúsculas marca o lugar do valor que você deve escrever depois do-q. - [-e]
- Opcional e sem valor: é uma opção liga/desliga.
- {chocolate,cenoura,milho}
- Entre chaves: as escolhas permitidas para o sabor.
Agora, vários jeitos de chamar:
$ python3 encomenda.py Bia cenoura Cliente: Bia Bolo de cenoura x 1 Retirar na padaria. $ python3 encomenda.py Bia cenoura --quantidade 3 --entrega Cliente: Bia Bolo de cenoura x 3 Entregar em casa. $ python3 encomenda.py Bia cenoura -q 3 -e Cliente: Bia Bolo de cenoura x 3 Entregar em casa. $ python3 encomenda.py -e Bia -q 2 milho Cliente: Bia Bolo de milho x 2 Entregar em casa. $ python3 encomenda.py Bia cenoura --quantidade=4 Cliente: Bia Bolo de cenoura x 4 Retirar na padaria. $ python3 encomenda.py "Dona Rosa" chocolate Cliente: Dona Rosa Bolo de chocolate x 1 Retirar na padaria.
- Sem
-q, a quantidade é odefault, 1. Sem-e,args.entregaéFalse. -q 3e--quantidade 3são a mesma coisa;--quantidade=4, com=, também vale.- As opções podem vir em qualquer ordem, até no meio dos posicionais (
-e Bia -q 2 milho). Os posicionais é que precisam manter a ordem entre eles: primeiro o cliente, depois o sabor. - Nome com espaço vai entre aspas:
"Dona Rosa".
O que tem dentro de args
O parse_args() devolve um objeto do tipo Namespace ("espaço de nomes"), que é só um saco de valores com nome. Dá para imprimi-lo inteiro, e repare que o type=int funcionou:
import argparse
parser = argparse.ArgumentParser(suggest_on_error=True)
parser.add_argument("sabor", choices=["chocolate", "cenoura", "milho"])
parser.add_argument("-q", "--quantidade", type=int, default=1)
args = parser.parse_args()
print(args)
print(type(args.quantidade))
$ python3 ver.py cenoura -q 2 Namespace(sabor='cenoura', quantidade=2) <class 'int'>
quantidade=2, sem aspas: é número, pronto para fazer conta. (O suggest_on_error=True você vai entender em Quando dá errado.)
Missão: nesta caixa o programa é chamado como python3 main.py Bia cenoura -q 3. Cada bolo custa R$ 35, mas o total sai como um monte de 3 seguidos. Acrescente type=int na opção --quantidade para o total sair Total: R$ 105.
import argparse
parser = argparse.ArgumentParser(description="Calcula o preço da encomenda.")
parser.add_argument("cliente")
parser.add_argument("sabor")
parser.add_argument("-q", "--quantidade", default=1)
args = parser.parse_args()
print(f"Cliente: {args.cliente}")
print(f"Total: R$ {args.quantidade * 35}")
import argparse
parser = argparse.ArgumentParser(description="Calcula o preço da encomenda.")
parser.add_argument("cliente")
parser.add_argument("sabor")
parser.add_argument("-q", "--quantidade", type=int, default=1)
args = parser.parse_args()
print(f"Cliente: {args.cliente}")
print(f"Total: R$ {args.quantidade * 35}")
4. Vários valores: nargs="+"
E se o número de argumentos variar? A lista de compras pode ter dois itens ou vinte. nargs (de "número de argumentos") com "+" quer dizer "um ou mais", e o valor vira uma lista:
import argparse
parser = argparse.ArgumentParser(description="Monta a lista de compras.")
parser.add_argument("itens", nargs="+", help="o que comprar")
args = parser.parse_args()
print("Itens:", args.itens)
for numero, item in enumerate(args.itens, start=1):
print(f"{numero}. {item}")
$ python3 compras.py farinha ovos "leite condensado" Itens: ['farinha', 'ovos', 'leite condensado'] 1. farinha 2. ovos 3. leite condensado $ python3 compras.py usage: compras.py [-h] itens [itens ...] compras.py: error: the following arguments are required: itens
O enumerate numera os itens (aula enumerate() e zip()). Na linha de uso, itens [itens ...] quer dizer "um item, e mais quantos quiser". Com nargs="*" seria "zero ou mais": aí a lista pode vir vazia, sem erro.
Formas diferentes de receber informação
| Jeito | Quando usar |
|---|---|
input() | Programas que conversam com a pessoa, uma pergunta de cada vez (um jogo, um questionário) |
sys.argv | Um script rapidinho, só para você, com um ou dois argumentos e sem conferência |
argparse | Qualquer programa de terminal que outras pessoas (ou você daqui a um mês) vão usar: confere, converte, explica os erros e tem --help |
| Argumento | Como declarar | Como chamar | O que chega |
|---|---|---|---|
| Posicional | add_argument("cliente") | Bia | args.cliente == "Bia" |
| Opcional com valor | add_argument("-q", "--quantidade", type=int, default=1) | -q 3, --quantidade 3, --quantidade=3 | args.quantidade == 3 (ou 1, se não vier) |
| Liga/desliga | add_argument("-e", "--entrega", action="store_true") | -e ou --entrega | True (ou False, se não vier) |
| Vários valores | add_argument("itens", nargs="+") | farinha ovos | args.itens == ["farinha", "ovos"] |
Quando dá errado
Todos os erros do argparse têm a mesma forma: a linha usage: (para você lembrar como se chama) e uma linha error: dizendo o que houve. E todos saem com o código 2.
$ python3 encomenda.py Bia
usage: encomenda.py [-h] [-q QUANTIDADE] [-e]
cliente {chocolate,cenoura,milho}
encomenda.py: error: the following arguments are required: sabor
"Os seguintes argumentos são obrigatórios: sabor". A Bia virou o cliente, e o sabor não veio. Como consertar: python3 encomenda.py Bia cenoura.
$ python3 encomenda.py Bia morango
usage: encomenda.py [-h] [-q QUANTIDADE] [-e]
cliente {chocolate,cenoura,milho}
encomenda.py: error: argument sabor: invalid choice: 'morango' (choose from chocolate, cenoura, milho)
"Argumento sabor: escolha inválida: 'morango' (escolha entre chocolate, cenoura, milho)". O choices barrou um sabor que a padaria não faz. E se o erro for de digitação? No Python 3.14, a opção suggest_on_error=True do ArgumentParser (do ver.py, lá em cima) faz o argparse sugerir o nome certo:
$ python3 ver.py cenora
usage: ver.py [-h] [-q QUANTIDADE] {chocolate,cenoura,milho}
ver.py: error: argument sabor: invalid choice: 'cenora', maybe you meant 'cenoura'? (choose from chocolate, cenoura, milho)
"Talvez você quisesse dizer 'cenoura'?". Num Python mais antigo, o suggest_on_error não existe e dá erro: deixe-o de fora se o programa tiver de rodar no 3.13.
$ python3 encomenda.py Bia cenoura -q três
usage: encomenda.py [-h] [-q QUANTIDADE] [-e]
cliente {chocolate,cenoura,milho}
encomenda.py: error: argument -q/--quantidade: invalid int value: 'três'
"Valor inteiro inválido: 'três'". O type=int tentou converter e não deu. Repare que o programa nem começou: o erro aparece antes de qualquer print. Como consertar: -q 3.
$ python3 encomenda.py Bia cenoura -q
usage: encomenda.py [-h] [-q QUANTIDADE] [-e]
cliente {chocolate,cenoura,milho}
encomenda.py: error: argument -q/--quantidade: expected one argument
$ echo $?
2
"Esperava um argumento": o -q precisa de um número depois dele.
$ python3 encomenda.py Bia cenoura --qtd 2
usage: encomenda.py [-h] [-q QUANTIDADE] [-e]
cliente {chocolate,cenoura,milho}
encomenda.py: error: unrecognized arguments: --qtd 2
$ python3 saudacao.py Bia Carla
usage: saudacao.py [-h] nome
saudacao.py: error: unrecognized arguments: Carla
"Argumentos não reconhecidos". No primeiro, --qtd não foi declarada. No segundo, o programa espera um nome só e sobrou a Carla. Como consertar: confira os nomes com --help; para dois nomes, use nargs="+", ou aspas se for um nome com espaço.
$ python3 encomenda.py Bia cenoura --quantidad 2 Cliente: Bia Bolo de cenoura x 2 Retirar na padaria.
Faltou o e do fim, e funcionou! O argparse aceita o começo de uma opção longa, desde que só uma opção comece assim. É cômodo, mas pode esconder erros de digitação, e um script que usa --quantidad quebra no dia em que alguém criar outra opção começando com essas letras. Como evitar: escreva sempre o nome inteiro; quem quiser proibir pode criar o parser com argparse.ArgumentParser(allow_abbrev=False).
argparse: o IndexError
Você já viu na seção 1: nome = sys.argv[1] sem argumento dá IndexError: list index out of range, com um traceback que não diz nada a quem só queria usar o programa. É o principal motivo para trocar o sys.argv pelo argparse.
Referência rápida
| Código | O que faz |
|---|---|
sys.argv | A lista crua: [programa, arg1, arg2, …], tudo texto |
parser = argparse.ArgumentParser(description="…") | Cria o analisador |
parser.add_argument("nome") | Argumento posicional (obrigatório) |
parser.add_argument("-q", "--quantidade") | Opção com valor (opcional; sem default, vale None) |
help="…" | Texto da ajuda |
type=int (ou float) | Converte o valor |
default=1 | Valor quando a opção não vem |
choices=[…] | Só aceita esses valores |
action="store_true" | Liga/desliga: True se aparecer |
nargs="+" / nargs="*" | Um ou mais / zero ou mais valores, numa lista |
args = parser.parse_args() | Lê o sys.argv, confere e devolve os valores (args.nome…) |
ArgumentParser(suggest_on_error=True) | 3.14 Sugere o nome certo em erros de digitação |
ArgumentParser(allow_abbrev=False) | Não aceita opções abreviadas |
| Mensagem | Quer dizer |
|---|---|
the following arguments are required: X | Faltou o argumento obrigatório X |
unrecognized arguments: … | Opção que não existe, ou argumento sobrando |
invalid choice: '…' (choose from …) | Valor fora do choices |
invalid int value: '…' | O type=int não conseguiu converter |
expected one argument | A opção veio sem o valor |
IndexError: list index out of range (com sys.argv) | Pediu um argumento que não veio |
Exercícios
1. O primeiro argumento
Em python3 ola.py Bia, qual índice de sys.argv guarda o 'Bia'?
2. Ler os argumentos
Complete a linha que analisa os argumentos e guarda o resultado:
3. Uma opção liga/desliga
Complete para que --urgente não receba valor e valha True quando aparecer:
4. Com parser.add_argument("-q", "--quantidade", type=int, default=1), o que vale args.quantidade se a pessoa não escrever -q?
5. python3 dobro.py 21, com print(sys.argv[1] * 2), mostra 2121. Por quê?
6. Qual chamada está certa para encomenda.py (cliente, sabor, -q, -e)?
Missão final: o desconto de quem retira
Missão: o programa é chamado como python3 main.py Bia milho -q 2. Cada bolo custa R$ 35,00, e quem não pede entrega ganha 10% de desconto. Acrescente a opção -e/--entrega com action="store_true" e calcule: sem entrega, o total é quantidade * 35 * 0.9. Aqui, sem -e, tem de sair Total: R$ 63.00.
import argparse
parser = argparse.ArgumentParser(description="Calcula o preço da encomenda.")
parser.add_argument("cliente")
parser.add_argument("sabor")
parser.add_argument("-q", "--quantidade", type=int, default=1)
# acrescente aqui a opção --entrega
args = parser.parse_args()
total = args.quantidade * 35
print(f"Total: R$ {total:.2f}")
import argparse
parser = argparse.ArgumentParser(description="Calcula o preço da encomenda.")
parser.add_argument("cliente")
parser.add_argument("sabor")
parser.add_argument("-q", "--quantidade", type=int, default=1)
parser.add_argument("-e", "--entrega", action="store_true")
args = parser.parse_args()
total = args.quantidade * 35
if not args.entrega:
total = total * 0.9
print(f"Total: R$ {total:.2f}")
Se o comando tivesse -e no fim (python3 main.py Bia milho -q 2 -e), o total seria R$ 70.00, sem desconto.
Resumo
- Argumentos de linha de comando são o que vem depois do nome do programa:
python3 encomenda.py Bia cenoura -q 3. sys.argvé a lista crua: o item 0 é o programa, e tudo chega como texto. Faltou um?IndexError.argparse: crie oArgumentParser, declare cada argumento comadd_argumente leia comargs = parser.parse_args().- Sem tracinho: posicional e obrigatório. Com
-q/--quantidade: opcional, em qualquer ordem. type=intconverte,defaultdá o valor padrão,choiceslimita,action="store_true"faz um liga/desliga,nargs="+"aceita vários.- O
--helpsai pronto, e os erros vêm comusage:eerror:, saindo com o código 2.