Unidade 6 · o tombo
O tombo
Quando algo é “excepcional” no programa, não é elogio: deu errado. SyntaxError você conserta. ValueError no teclado, arquivo que não existe no caderno — você antecipa.
bolo onde se espera número — e o caderno da unidade 5 some do disco (FileNotFoundError). try / except, else, loop até cooperar, uma função get_int reutilizável.
Uma aspas e o programa nem começa
Arquivo recado.py, uma linha só, e você esquece de fechar as aspas:
print("Café na máquina.
Rode python recado.py. O traceback é maior que o programa. O que importa está embaixo: SyntaxError, unterminated string literal — você começou um texto e não terminou. Literal é o que você digitou entre aspas, não uma variável.
Erro de sintaxe é problema seu, na hora de escrever. Não tem except que pegue: o interpretador recusa o arquivo inteiro. Fecha a aspas, rode de novo, aparece o café.
O outro tipo: enquanto roda
Muita coisa só quebra depois que o programa já começou — em especial o que um humano digita. Você não adivinha o teclado. Por isso escreve código defensivo: detecta o problema e decide o que fazer, em vez de deixar o traceback na cara do caixa.
Arquivo novo, quantidade.py. Pergunta um inteiro, imprime o valor. Conversão com int, texto com f-string:
qtd = int(input("Quantos pães? "))
print(f"São {qtd} pães.")
50 funciona. Cantos que vale testar: 0, -1. Também funcionam — são inteiros. Agora o canto que não parece número: bolo.
Aí não é SyntaxError. Você não esqueceu gramática. É ValueError: invalid literal for int() with base 10: 'bolo'. Base 10 é o decimal de sempre. O int recusou o texto.
Imprimir “não digite bolo” não resolve: a pessoa não lê, ou tenta derrubar o programa de propósito. O caminho é tratar o erro.
int("bolo") sem try. O que acontece?
Tentar, salvo se der errado
try é o nome certo: tente fazer isto. except ValueError — as maiúsculas importam — é o que roda se essa família de erro aparecer. SyntaxError, de novo, não entra aqui.
try:
qtd = int(input("Quantos pães? "))
print(f"São {qtd} pães.")
except ValueError:
print("Não é um inteiro.")
Indentação: o que está sob o try é o que você tenta; o que está sob o except só roda no erro. 50 imprime a quantidade. bolo imprime o recado — sem traceback.
Um try com except (ValueError ou Exception) em volta de uma conversão.
try: n = int(input("n: "))except ValueError: print("Não é número.")Não pegue o mundo inteiro
ValueError não é o único erro. Tem NameError, ZeroDivisionError, e uma lista que só cresce com os anos. A técnica é a mesma: nomeie o que você sabe tratar.
Dá para escrever except: sem tipo e engolir tudo. É preguiça. Esconde o bug que você queria ver no traceback. Melhor prática: descobrir que erro aquela função levanta e escrever o nome. A documentação oficial nem sempre avisa de antemão; vem com a prática.
Por que evitar except: nu (sem nomear o erro)?
Tente o mínimo
O print da quantidade não levanta ValueError: f-string imprime int, str, float. Melhor prática: tente só a linha que pode quebrar — a conversão — e tire o print do try.
try:
qtd = int(input("Quantos pães? "))
except ValueError:
print("Não é um inteiro.")
print(f"São {qtd} pães.")
50 ainda funciona. bolo agora vira NameError: name 'qtd' is not defined, na linha do print.
Não é escopo de bloco (isso é C, C++, Java). Também não é variável “local ao try”. É ordem: o = copia da direita para a esquerda. input devolve string; int("bolo") explode antes de copiar. A esquerda nunca roda. qtd não existe. O print de baixo, alinhado à esquerda, executa de qualquer jeito.
Por que qtd “não está definido” se a linha do = está no arquivo?
Se deu certo, então
O else do if você já viu. No try a intuição é a mesma: o resto, quando ninguém explodiu. Assim o print da quantidade só roda no sucesso; o except e o else se excluem.
try:
qtd = int(input("Quantos pães? "))
except ValueError:
print("Não é um inteiro.")
else:
print(f"São {qtd} pães.")
50: tenta, copia, pula o except, entra no else. bolo: tenta, except, não entra no else — e qtd não é usado.
Qual a diferença entre else e finally no try?
with do caderno, unidade 5, já usa essa ideia.)Perguntar de novo, não desistir
Mandar o usuário embora depois de um bolo é hostil. Na unidade 3 o loop já insistia até o número prestar. Aqui o mesmo: while True — pergunta verdadeira de propósito — e break quando a conversão der certo.
while True:
try:
qtd = int(input("Quantos pães? "))
except ValueError:
print("Não é um inteiro.")
else:
break
print(f"São {qtd} pães.")
O else ainda é do try, não do except. bolo, cão, ave: recado e pergunta de novo. 50: break, print fora do loop.
Se você meter o print dentro do loop e tirar o break, o programa nunca acaba: 50, 49, 48… Feature, se você quiser. Senão, precisa sair.
break vale em loop, em if, em try. Dá para pôr o break logo após a atribuição, ainda no try, e largar o else. Se int falhar, o fluxo pula para o except e o break nem roda. Os dois desenhos são corretos; o else deixa o try com uma linha só. Escolha o que você justifica, não o que “passou”.
Uma função que pede inteiro
Hoje e amanhã você vai querer inteiro do teclado. Invente get_int. O trabalho de perguntar some da vista do main — abstração, como na unidade 4.
def get_int():
while True:
try:
qtd = int(input("Quantos pães? "))
except ValueError:
print("Não é um inteiro.")
else:
return qtd
def main():
qtd = get_int()
print(f"São {qtd} pães.")
main()
return é mais forte que break: sai do loop e da função, devolvendo o valor. Não precisa break e depois return na linha de baixo.
Ainda mais curto: se a variável só serve para devolver na hora, return int(input(...)) dentro do try. Menos linhas, menos lugar para errar; um pouco mais denso de ler. Os dois valem se você souber dizer por quê.
Uma função com return e conversão int(...) (o miolo de um get_int).
def get_int():
while True:
try:
return int(input("Quantos? "))
except ValueError:
passPegar o erro e não falar nada
“Não é um inteiro” três vezes cansa. Se quiser só perguntar de novo, capture o erro e pass — a palavra da unidade 2: sua vez de falar, e você passa. O traceback não aparece; o loop continua; o convite Quantos pães? se repete.
def get_int():
while True:
try:
return int(input("Quantos pães? "))
except ValueError:
pass
Quem chamou get_int não fica sabendo que houve erro: o ponto de tratar é este. Recado explícito ou silêncio — os dois são mecanismos; escolha o que ajuda o humano na fila.
Indentação, de novo: o que está sob def é a função; sob while, o loop; sob try, a linha que tenta; sob except, o pass. Não é enfeite. É o que associa cada bloco a quem manda executar.
Dá para checar str.isdigit() (ou afins) antes do int. É razoável. O jeito desta linguagem costuma ser: tente, e trate se falhar — em vez de uma floresta de if na frente.
No except ValueError: pass dentro do while True, o que o pass faz?
Quem chama diz o convite
Hard-coded “Quantos pães?” prende a função a um programa só. O input nativo já recebe o texto do convite. Faça o mesmo: get_int ganha um parâmetro prompt. O main manda a frase; a função não precisa saber se a gaveta se chama qtd, y ou z.
def get_int(prompt):
while True:
try:
return int(input(prompt))
except ValueError:
pass
def main():
qtd = get_int("Quantos pães? ")
print(f"São {qtd} pães.")
main()
Mesmo comportamento; código mais reutilizável. Quem usa a função (caller) não precisa coincidir o nome da variável com quem é chamado (callee).
Você também pode disparar o erro
raise ValueError("precisa ser positivo") recusa um valor seu — mesa com zero pessoas, quantidade negativa. Quem chamou trata ou o programa cai, honesto. Não é o mesmo que sys.exit (unidade 7): exit encerra o script; raise é para o except do colega. Nesta unidade o miolo é capturar; disparar aparece de novo quando a função valida de propósito.
Uma linha (ou bloco) com raise e um erro nomeado.
raise ValueError("precisa ser positivo")Oficina · get_int
try / except ValueError. Pode imprimir recado ou só pass. Opcional: parâmetro prompt. Arquivo: quantidade.py.
Cole o programa: input + try/except (função vale).
def get_int(prompt):
while True:
try:
return int(input(prompt))
except ValueError:
pass
n = get_int("Quantos pães? ")
print(n)