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ê.

Você vai aprender
  • O que são argumentos de linha de comando, e como o Python os entrega em sys.argv.
  • Por que sys.argv sozinho dá trabalho (o IndexError, 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 --help que o argparse gera 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çaExemploO que é
O programapython3 encomenda.pyO Python e o arquivo que ele vai rodar
Argumento posicionalBia, cenouraVale pela posição: o primeiro é o cliente, o segundo é o sabor
Opção com valor--quantidade 3Um nome que começa com -- (ou -), seguido do valor
Opção liga/desliga--entregaSó 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 3 chegou 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 argparse sai 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 argparse são em inglês; os seus (a descrição, as ajudas de cada argumento) saem como você escrever.
Ajuda colorida 3.14

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.")
ParteO 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=intConverte o texto para número inteiro (e reclama se não der)
default=1O 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. QUANTIDADE em 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 é o default, 1. Sem -e, args.entrega é False.
  • -q 3 e --quantidade 3 sã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

JeitoQuando usar
input()Programas que conversam com a pessoa, uma pergunta de cada vez (um jogo, um questionário)
sys.argvUm script rapidinho, só para você, com um ou dois argumentos e sem conferência
argparseQualquer programa de terminal que outras pessoas (ou você daqui a um mês) vão usar: confere, converte, explica os erros e tem --help
ArgumentoComo declararComo chamarO que chega
Posicionaladd_argument("cliente")Biaargs.cliente == "Bia"
Opcional com valoradd_argument("-q", "--quantidade", type=int, default=1)-q 3, --quantidade 3, --quantidade=3args.quantidade == 3 (ou 1, se não vier)
Liga/desligaadd_argument("-e", "--entrega", action="store_true")-e ou --entregaTrue (ou False, se não vier)
Vários valoresadd_argument("itens", nargs="+")farinha ovosargs.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.

Faltou um argumento obrigatório
$ 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.

Um valor fora das escolhas
$ 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.

Texto onde devia ser número
$ 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.

A opção sem o valor
$ 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.

Uma opção que não existe (e o argumento a mais)
$ 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.

A abreviação que passa calada
$ 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).

Sem 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ódigoO que faz
sys.argvA 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=1Valor 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
MensagemQuer dizer
the following arguments are required: XFaltou 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 argumentA 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'?

sys.argv[]

2. Ler os argumentos

Complete a linha que analisa os argumentos e guarda o resultado:

args = parser.()

3. Uma opção liga/desliga

Complete para que --urgente não receba valor e valha True quando aparecer:

parser.add_argument("--urgente", action="")

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 o ArgumentParser, declare cada argumento com add_argument e leia com args = parser.parse_args().
  • Sem tracinho: posicional e obrigatório. Com -q/--quantidade: opcional, em qualquer ordem.
  • type=int converte, default dá o valor padrão, choices limita, action="store_true" faz um liga/desliga, nargs="+" aceita vários.
  • O --help sai pronto, e os erros vêm com usage: e error:, saindo com o código 2.