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.

Você vai aprender
  • O else do try: quando ele roda e por que ele ajuda a deixar o try pequeno.
  • Um erro real que um try grande demais esconde, e como o else o 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.
  • try com finally e sem except; o finally com return e break.
  • O aviso novo do Python 3.14 para return dentro do finally, 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:

  1. Tente (try): bater a massa e colocar no forno.
  2. Se der problema (except): se a massa desandar, jogue fora e avise.
  3. Se não deu problema (else): decore o bolo e sirva.
  4. 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 do try e do except, e vem depois de todos os except.
print(f"Ano que vem…")
Só roda se a conversão deu certo. Aqui, idade com 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.

É o mesmo 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.

A regra

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 try e vem por último, depois dos except (e do else, se houver).
print("Forno desligado.")
Roda sempre: depois do try que deu certo, depois do except que 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
BlocoSem erroErro tratado (tem except)Erro não tratado
tryRoda inteiroAté a linha do erroAté a linha do erro
exceptPuladoRoda (o primeiro que combina)Pulado (nenhum combina)
elseRodaPuladoPulado
finallyRodaRodaRoda, e depois aparece o traceback
Depois do tryRodaRodaNã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.

FormaQuando usar
Tudo no tryProgramas bem curtos, em que a linha de baixo não tem como dar o mesmo tipo de erro
try + except + elseO 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
finallyPara 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.

Achar que o 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

BlocoRoda quandoObrigatório?
try:Sempre (até um erro, se houver)Sim
except Tipo:Aconteceu um erro daquele tipo no tryPelo menos um except ou o finally
else:O try terminou sem erroNão; só junto com except
finally:Sempre, por último; até com erro não tratado, return ou breakNão
SintomaCausa provável
SyntaxError: expected 'except' or 'finally' block apontando o elseelse antes do except, ou try/else sem except
SyntaxError: invalid syntax apontando um exceptexcept depois do finally
SyntaxWarning: 'return' in a 'finally' blockreturn (ou break/continue) no finally: pode engolir erros
O except mostra uma mensagem que não faz sentidotry 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):

try: n = int(texto) except ValueError: print("inválido") : print(n * 2) : print("fim")

2. Quantas linhas?

Com texto = "abc", quantas linhas o programa do exercício 1 mostra?

linhas

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 dos except): roda só se o try terminou sem erro. Use-o para deixar no try só a linha arriscada.
  • Um erro dentro do else não é pego pelos except de cima: é assim que o else revela defeitos que um try grande esconderia.
  • finally (por último): roda sempre, com erro tratado, sem erro e até com erro não tratado (antes do traceback), return ou break.
  • A ordem é try → except → else → finally. O try precisa de um except ou de um finally; o else exige except.
  • try + finally sem except: arruma a casa e deixa o erro aparecer.
  • No finally, nada de return, break ou continue: eles engolem erros, e o Python 3.14 avisa com SyntaxWarning.