Python else e finally
Na aula try e except, o try tinha dois blocos: o plano A e o plano B. Ele pode ter mais dois. O else ("senão") guarda o que deve rodar só se deu tudo certo. O finally ("finalmente") guarda o que deve rodar sempre, com erro ou sem erro: desligar o forno, fechar o caixa, avisar que acabou.
- O
elsedotry: quando ele roda e por que ele ajuda a deixar otrypequeno. - Um erro real que um
trygrande demais esconde, e como oelseo revela. - O
finally: roda sempre, até quando o erro não foi tratado e o programa vai parar. - A ordem completa (
try,except,else,finally) e o caminho do Python em cada caso. trycomfinallye semexcept; ofinallycomreturnebreak.- O aviso novo do Python 3.14 para
returndentro dofinally, e os erros de ordem.
Todos os programas desta aula rodaram no Python 3.14 da máquina da Ana (usuária ana, computador notebook) com python3 arquivo.py. O que aparece depois de cada pergunta é o que a Ana digitou.
A ideia: assar o bolo
A receita de bolo da Ana, com os quatro blocos:
- Tente (
try): bater a massa e colocar no forno. - Se der problema (
except): se a massa desandar, jogue fora e avise. - Se não deu problema (
else): decore o bolo e sirva. - Em qualquer caso (
finally): desligue o forno.
Repare que decorar o bolo não é uma coisa "perigosa": não precisa de plano B. Ela só faz sentido se o bolo deu certo, por isso fica no else, e não no try. E desligar o forno não depende de nada: tem de acontecer, deu certo ou não. Esquecer o forno ligado porque a massa desandou seria um desastre maior.
1. else: só se não houve erro
try:
idade = int(input("Sua idade: "))
except ValueError:
print("Isso não é um número inteiro.")
else:
print(f"Ano que vem você terá {idade + 1} anos.")
print("Obrigado!")
- try:
- Agora com uma linha só: a que pode dar
ValueError. - except ValueError:
- O plano B, igual ao da aula anterior.
- else:
- "Senão": se não aconteceu nenhum erro no
try. Fica na mesma coluna dotrye doexcept, e vem depois de todos osexcept. - print(f"Ano que vem…")
- Só roda se a conversão deu certo. Aqui,
idadecom certeza é um número. - print("Obrigado!")
- Fora de tudo: roda nos dois casos.
$ python3 else1.py Sua idade: 30 Ano que vem você terá 31 anos. Obrigado! $ python3 else1.py Sua idade: trinta Isso não é um número inteiro. Obrigado!
A saída é a mesma do idade_try.py da aula try e except, que tinha as duas linhas dentro do try. Então para que o else? Para deixar claro qual linha o except está protegendo. E isso faz diferença, como mostra a próxima seção.
else do if?
A palavra é a mesma, e a ideia é parecida: "senão". No if, o else roda quando a condição é falsa. No try, ele roda quando não houve erro (o except não foi usado). Há ainda um terceiro else, o dos laços, com aula própria: else nos Laços.
2. O erro que o try grande esconde
A padaria da Ana tem um programa que mostra o preço de um produto e o preço na promoção. Tudo está dentro do try, e há um defeito: a linha da promoção procura uma chave 'promocao' que não existe no dicionário.
precos = {"pão": 0.75, "leite": 5.49}
produto = input("Produto: ")
try:
preco = precos[produto]
print(f"{produto}: R$ {preco:.2f}")
print(f"Na promoção: R$ {precos['promocao']:.2f}")
except KeyError:
print(f"Não vendemos {produto}.")
$ python3 tudo_no_try.py Produto: pão pão: R$ 0.75 Não vendemos pão.
"O pão custa R$ 0,75" e, logo embaixo, "não vendemos pão". O except KeyError foi escrito para um produto que não existe, mas pegou o KeyError da linha da promoção, que é outro problema, e mostrou a mensagem errada. Nenhum traceback, nenhuma pista. Agora com else, deixando no try só a linha que procura o produto:
precos = {"pão": 0.75, "leite": 5.49}
produto = input("Produto: ")
try:
preco = precos[produto]
except KeyError:
print(f"Não vendemos {produto}.")
else:
print(f"{produto}: R$ {preco:.2f}")
print(f"Na promoção: R$ {precos['promocao']:.2f}")
$ python3 com_else.py
Produto: pão
pão: R$ 0.75
Traceback (most recent call last):
File "/home/ana/com_else.py", line 9, in <module>
print(f"Na promoção: R$ {precos['promocao']:.2f}")
~~~~~~^^^^^^^^^^^^
KeyError: 'promocao'
$ python3 com_else.py
Produto: café
Não vendemos café.
Agora o defeito aparece com nome e endereço: KeyError: 'promocao', linha 9. O except protege só o try; um erro dentro do else não é pego por ele e aparece normalmente. E o caso que o except devia tratar (o café, que a padaria não vende) continua funcionando.
No try, só a linha que pode dar o erro esperado. O que depende de ela ter dado certo vai no else. Assim, cada except trata exatamente o que você previu, e os erros que você não previu aparecem.
Missão: o programa funciona, mas o try tem duas linhas. Deixe no try só a conversão e mova o print do "ano que vem" para um else: (depois do except). A caixa vai "digitar" 30.
try:
idade = int(input("Sua idade: "))
print(f"Ano que vem você terá {idade + 1} anos.")
except ValueError:
print("Isso não é um número inteiro.")
print("Obrigado!")
try:
idade = int(input("Sua idade: "))
except ValueError:
print("Isso não é um número inteiro.")
else:
print(f"Ano que vem você terá {idade + 1} anos.")
print("Obrigado!")
3. finally: aconteça o que acontecer
print("Forno ligado.")
try:
minutos = int(input("Minutos de forno: "))
print(f"Assando por {minutos} minutos...")
except ValueError:
print("Tempo inválido.")
finally:
print("Forno desligado.")
print("Fim da receita.")
- finally:
- "Finalmente". Fica na mesma coluna do
trye vem por último, depois dosexcept(e doelse, se houver). - print("Forno desligado.")
- Roda sempre: depois do
tryque deu certo, depois doexceptque tratou um erro e até quando um erro não foi tratado.
$ python3 finally1.py Forno ligado. Minutos de forno: 40 Assando por 40 minutos... Forno desligado. Fim da receita. $ python3 finally1.py Forno ligado. Minutos de forno: quarenta Tempo inválido. Forno desligado. Fim da receita.
Nos dois casos, o forno foi desligado. Até aqui, um print fora do try faria o mesmo. A diferença aparece quando o erro não é tratado. Esta versão calcula quantas fornadas cabem numa hora, e a Ana digita 0:
print("Forno ligado.")
try:
minutos = int(input("Minutos de forno: "))
print(f"Cada fornada: {60 / minutos:.1f} por hora")
except ValueError:
print("Tempo inválido.")
finally:
print("Forno desligado.")
print("Fim da receita.")
$ python3 finally_nt.py
Forno ligado.
Minutos de forno: 0
Forno desligado.
Traceback (most recent call last):
File "/home/ana/finally_nt.py", line 4, in <module>
print(f"Cada fornada: {60 / minutos:.1f} por hora")
~~~^~~~~~~~~
ZeroDivisionError: division by zero
$ echo $?
1
Olhe a ordem: o ZeroDivisionError não tem except, então o programa vai parar. Mas, antes de parar, o Python rodou o finally (Forno desligado.) e só depois mostrou o traceback. O Fim da receita., que estava fora do try, não apareceu. É para isso que o finally existe: a arrumação acontece até no pior caso.
4. Os quatro juntos
Um programa que anuncia cada passo, para ver o caminho completo:
print("1. Antes")
try:
print("2. try: começou")
numero = int(input("Número: "))
print("3. try: converteu")
except ValueError:
print("4. except: não é número")
else:
print("5. else: deu tudo certo")
finally:
print("6. finally: sempre")
print("7. Depois")
$ python3 completo.py 1. Antes 2. try: começou Número: 7 3. try: converteu 5. else: deu tudo certo 6. finally: sempre 7. Depois $ python3 completo.py 1. Antes 2. try: começou Número: sete 4. except: não é número 6. finally: sempre 7. Depois
| Bloco | Sem erro | Erro tratado (tem except) | Erro não tratado |
|---|---|---|---|
try | Roda inteiro | Até a linha do erro | Até a linha do erro |
except | Pulado | Roda (o primeiro que combina) | Pulado (nenhum combina) |
else | Roda | Pulado | Pulado |
finally | Roda | Roda | Roda, e depois aparece o traceback |
Depois do try | Roda | Roda | Não roda: o programa parou |
A ordem de escrever é sempre esta: try, os except, o else, o finally. Só o try é obrigatório, e ele precisa de pelo menos um except ou um finally. O else só pode aparecer se houver except.
5. try e finally, sem except
Às vezes você não sabe (ou não quer) tratar o erro, mas precisa arrumar a casa antes de o programa parar. Aí vale um try só com finally:
print("Caixa aberto.")
try:
valor = float(input("Valor da venda: "))
print(f"Venda de R$ {valor:.2f} registrada.")
finally:
print("Caixa fechado.")
$ python3 try_finally.py
Caixa aberto.
Valor da venda: 12.50
Venda de R$ 12.50 registrada.
Caixa fechado.
$ python3 try_finally.py
Caixa aberto.
Valor da venda: doze
Caixa fechado.
Traceback (most recent call last):
File "/home/ana/try_finally.py", line 3, in <module>
valor = float(input("Valor da venda: "))
ValueError: could not convert string to float: 'doze'
O erro não foi tratado (o traceback aparece, e a mensagem do float() é "não deu para converter o texto em float"), mas o caixa foi fechado antes. O uso mais comum disso na vida real é fechar um arquivo aconteça o que acontecer; para arquivos, porém, o Python tem um jeito ainda melhor, o with, que você vai ver na aula Abrindo Arquivos.
Missão: a caixa vai "digitar" doze, e o programa vai parar com ValueError (deixe parar; o erro não é para tratar). Mas o caixa precisa ser fechado mesmo assim. Coloque as duas linhas da venda num try e o print("Caixa fechado.") num finally.
print("Caixa aberto.")
valor = float(input("Valor da venda: "))
print(f"Venda de R$ {valor:.2f} registrada.")
print("Caixa fechado.")
print("Caixa aberto.")
try:
valor = float(input("Valor da venda: "))
print(f"Venda de R$ {valor:.2f} registrada.")
finally:
print("Caixa fechado.")
6. finally com return e break
O finally roda até quando o try sai "pela porta dos fundos". Numa função, o return sai da função; mas, se ele estiver dentro de um try, o finally roda antes:
def ler_quantidade(texto):
try:
return int(texto)
except ValueError:
return 0
finally:
print(f"(conferido: {texto})")
print(ler_quantidade("12"))
print(ler_quantidade("doze"))
$ python3 func_return.py (conferido: 12) 12 (conferido: doze) 0
Repare na ordem: o (conferido: …) aparece antes do número. O return já tinha decidido o valor (12, ou 0 no caso do except), mas antes de a função entregar esse valor ao print de fora, o finally rodou. Com o break de um laço (veja break e continue) é igual:
for tentativa in range(1, 4):
try:
print(f"Tentativa {tentativa}")
if tentativa == 2:
break
finally:
print(" ...anotado no caderno")
print("Saiu do laço")
$ python3 laco_break.py Tentativa 1 ...anotado no caderno Tentativa 2 ...anotado no caderno Saiu do laço
Na tentativa 2, o break mandou sair do laço, e mesmo assim o finally anotou no caderno antes.
Formas diferentes de fazer a mesma coisa
"Só faça isto se a conversão deu certo" pode ser escrito de três jeitos:
try:
idade = int(input("Sua idade: "))
print(f"Ano que vem você terá {idade + 1} anos.")
except ValueError:
print("Isso não é um número inteiro.")
try:
idade = int(input("Sua idade: "))
except ValueError:
print("Isso não é um número inteiro.")
else:
print(f"Ano que vem você terá {idade + 1} anos.")
deu_certo = False
try:
idade = int(input("Sua idade: "))
deu_certo = True
except ValueError:
print("Isso não é um número inteiro.")
if deu_certo:
print(f"Ano que vem você terá {idade + 1} anos.")
$ python3 flag.py Sua idade: 30 Ano que vem você terá 31 anos.
Os três dão o mesmo resultado com 30 e com trinta. A terceira usa uma variável deu_certo como "bandeirinha" (os programadores dizem flag): ela vira True só se a conversão passou.
| Forma | Quando usar |
|---|---|
Tudo no try | Programas bem curtos, em que a linha de baixo não tem como dar o mesmo tipo de erro |
try + except + else | O recomendado: o except protege só a linha arriscada |
Bandeirinha (deu_certo) | Funciona, mas é mais comprido; o else faz o mesmo sem variável extra |
print depois do try (fora dele) | Para o que roda nos dois casos, se o erro foi tratado |
finally | Para o que roda sempre, até se o erro não foi tratado (fechar, desligar, avisar) |
Quando dá errado
else antes do except
try:
idade = int(input("Sua idade: "))
else:
print(f"Ano que vem você terá {idade + 1} anos.")
except ValueError:
print("Isso não é um número inteiro.")
$ python3 else_antes.py
File "/home/ana/else_antes.py", line 3
else:
^^^^
SyntaxError: expected 'except' or 'finally' block
"Esperava um bloco except ou finally." Logo depois do try, o Python exige um except ou um finally; o else só vem depois dos except. Como consertar: a ordem é try → except → else → finally. Um try com else e sem nenhum except dá exatamente a mesma mensagem: o else do try só existe junto com um except.
finally antes do except
try:
idade = int(input("Sua idade: "))
finally:
print("Pronto.")
except ValueError:
print("Isso não é um número inteiro.")
$ python3 finally_antes.py
File "/home/ana/finally_antes.py", line 5
except ValueError:
^^^^^^
SyntaxError: invalid syntax
Aqui a mensagem é só "sintaxe inválida", apontando o except. O try/finally das linhas 1 a 4 estava completo e certo; o except da linha 5 ficou solto, sem try. Como consertar: o finally é sempre o último.
return dentro do finally 3.14
def dividir(a, b):
try:
return a / b
finally:
return "resultado"
print(dividir(10, 0))
$ python3 return_finally.py /home/ana/return_finally.py:5: SyntaxWarning: 'return' in a 'finally' block return "resultado" resultado
A divisão por zero aconteceu e… sumiu. Um return no finally passa por cima de tudo: do valor do return do try e até de um erro não tratado. O programa terminou "bem", com uma resposta sem sentido. Por isso o Python 3.14 passou a mostrar um aviso (SyntaxWarning, "aviso de sintaxe"): "return num bloco finally". É um aviso, e não um erro: o programa ainda roda. Num Python 3.13, ele roda calado. O mesmo aviso aparece para break e continue dentro do finally. Como consertar: no finally, só arrumação (fechar, desligar, mostrar); nada de return, break ou continue.
except protege o else
Você viu na seção 2: um erro dentro do else não é tratado pelos except de cima. Isso é de propósito, mas pega quem coloca no else uma linha que pode dar o mesmo erro do try e espera que o except cuide dela. Se uma linha do else também precisa de plano B, ela merece o seu próprio try.
Referência rápida
| Bloco | Roda quando | Obrigatório? |
|---|---|---|
try: | Sempre (até um erro, se houver) | Sim |
except Tipo: | Aconteceu um erro daquele tipo no try | Pelo menos um except ou o finally |
else: | O try terminou sem erro | Não; só junto com except |
finally: | Sempre, por último; até com erro não tratado, return ou break | Não |
| Sintoma | Causa provável |
|---|---|
SyntaxError: expected 'except' or 'finally' block apontando o else | else antes do except, ou try/else sem except |
SyntaxError: invalid syntax apontando um except | except depois do finally |
SyntaxWarning: 'return' in a 'finally' block | return (ou break/continue) no finally: pode engolir erros |
O except mostra uma mensagem que não faz sentido | try grande demais: mova o resto para o else |
Exercícios
1. Complete os blocos
Complete com as palavras que faltam (o primeiro bloco só roda se não houve erro; o segundo roda sempre):
2. Quantas linhas?
Com texto = "abc", quantas linhas o programa do exercício 1 mostra?
3. Quando o bloco else de um try roda?
4. Um erro sem except acontece no try, e há um finally. O que aparece?
5. Qual é a ordem certa dos blocos?
Missão final: o caixa completo
Missão: a caixa vai "digitar" abc. Reescreva o programa com os quatro blocos: no try, só a conversão do valor; um except ValueError: que mostre Valor inválido, venda cancelada.; um else: com o print da venda registrada; e um finally: que mostre Caixa fechado.. Depois, troque o abc de cabeça: com 12.50, quais blocos rodariam?
print("Caixa aberto.")
valor = float(input("Valor da venda: "))
print(f"Venda de R$ {valor:.2f} registrada.")
print("Caixa fechado.")
print("Caixa aberto.")
try:
valor = float(input("Valor da venda: "))
except ValueError:
print("Valor inválido, venda cancelada.")
else:
print(f"Venda de R$ {valor:.2f} registrada.")
finally:
print("Caixa fechado.")
Resumo
else(depois dosexcept): roda só se otryterminou sem erro. Use-o para deixar notrysó a linha arriscada.- Um erro dentro do
elsenão é pego pelosexceptde cima: é assim que oelserevela defeitos que umtrygrande esconderia. finally(por último): roda sempre, com erro tratado, sem erro e até com erro não tratado (antes do traceback),returnoubreak.- A ordem é
try→except→else→finally. Otryprecisa de umexceptou de umfinally; oelseexigeexcept. try+finallysemexcept: arruma a casa e deixa o erro aparecer.- No
finally, nada dereturn,breakoucontinue: eles engolem erros, e o Python 3.14 avisa comSyntaxWarning.