
Passo 1 de 8
Reconstruir a sequência de chamadas pelo traceback
Leia um traceback com várias funções, reconstrua a ordem das chamadas e diferencie os chamadores da operação que realmente falhou.
Trilha de aprendizado · Nível 6 · Tutorial 1
Interpretar um traceback com várias chamadas e tratar falhas esperadas sem esconder erros inesperados, distinguindo os caminhos de execução dos blocos de tratamento.
Reconstruir a sequência de chamadas pelo traceback
Leia um traceback com várias funções, reconstrua a ordem das chamadas e diferencie os chamadores da operação que realmente falhou. 3 min
Tratar uma exceção específica no ponto certo
Use try e except para tratar um ValueError, acompanhar sua propagação entre funções e entender onde a execução continua. 4 min
Escolher entre tratamentos separados e agrupados
Organize capturas alternativas de acordo com a resposta necessária para cada tipo de falha e preserve a propagação de erros não previstos. 3 min
Separar o caminho de sucesso com else
Use else para executar somente as ações que dependem da conclusão bem-sucedida do bloco try e reconheça que falhas surgidas no próprio else continuam se propagando. 3 min
Executar ações de encerramento com finally
Preveja quando o bloco finally é executado e diferencie encerramento da estrutura de tratamento ou recuperação de uma exceção. 3 min
Evitar que finally altere o resultado da função
Reconheça como um return em finally pode substituir outro retorno ou ocultar uma exceção, e organize a função para preservar seu resultado real. 3 min
Restringir o tratamento às falhas esperadas
Reduza o escopo do try para tratar apenas falhas previstas pelo contexto e manter erros inesperados visíveis. 3 min
Aplicar e revisar os quatro blocos
Refatore um programa em memória, execute quatro cenários separadamente e interprete a falha que deve continuar visível. 4 min

Passo 1 de 8
Leia um traceback com várias funções, reconstrua a ordem das chamadas e diferencie os chamadores da operação que realmente falhou.
O script chama executar, que chama calcular_metade, que chama converter. O erro surge na função mais interna, mas o traceback também registra as chamadas que levaram até ela. Considere as linhas em branco ao acompanhar a numeração.
def converter(texto):
return int(texto)
def calcular_metade(texto):
numero = converter(texto)
return numero / 2
def executar():
return calcular_metade("dez")
executar()O caminho exibido para o arquivo pode variar no seu computador.
Traceback (most recent call last):
File "exemplo.py", line 14, in <module>
executar()
File "exemplo.py", line 11, in executar
return calcular_metade("dez")
File "exemplo.py", line 6, in calcular_metade
numero = converter(texto)
File "exemplo.py", line 2, in converter
return int(texto)
ValueError: invalid literal for int() with base 10: 'dez'Comece pela última linha: ValueError é o tipo da exceção, e o texto após os dois-pontos é sua mensagem. Depois, examine os quadros acima. Cada quadro informa o arquivo, o número da linha e o local de execução — uma função ou <module>, quando a linha está no nível principal do script.
Os quadros aparecem da chamada mais externa para o ponto mais interno apresentado: linha 14 → linha 11 → linha 6 → linha 2.

As linhas 14, 11 e 6 fazem chamadas. Na linha 2, a conversão int(texto) é a operação que falha.
Dica
Uma linha presente no traceback pode apenas ter chamado outra função. Neste exemplo, numero = converter(texto) conduz à função interna; quem realmente produz a exceção é int(texto), ao tentar converter "dez".
Relacione os quadros do traceback às ações executadas.
Toque em um item e depois no par correspondente.
Qual operação originou a exceção?

Passo 2 de 8
Use try e except para tratar um ValueError, acompanhar sua propagação entre funções e entender onde a execução continua.
Coloque no try a operação que pode produzir a falha esperada. Se int() não conseguir converter o texto, ele produz um ValueError: a execução abandona imediatamente o restante do try e procura um except compatível.
Execute mentalmente o código e observe que as mensagens 3 e 4 não são exibidas.
print("1. antes do try")
try:
print("2. iniciando a conversão")
quantidade = int("doze")
print("3. conversão concluída")
print(f"4. quantidade: {quantidade}")
except ValueError as erro:
print(f"5. entrada inválida: {erro}")
print("6. depois da estrutura")
A falha interrompe o try, desvia para o except compatível e, quando o tratamento termina normalmente, a execução continua depois da estrutura.
A conversão ocorre em converter, mas o tratamento está em mostrar_quantidade, que chamou essa função.
def converter(texto):
print("conversão iniciada")
numero = int(texto)
print("conversão terminada")
return numero
def mostrar_quantidade(texto):
try:
quantidade = converter(texto)
print(f"quantidade: {quantidade}")
except ValueError as erro:
print(f"não foi possível converter: {erro}")
print("fim de mostrar_quantidade")
mostrar_quantidade("três")O ValueError sai de converter e se propaga até o except ValueError no chamador. O tratamento não retoma a função no ponto interrompido: conversão terminada não é exibida, nem um valor é retornado por aquela chamada.
Em except ValueError as erro, a escolha do tratamento depende do tipo ValueError. O nome erro dá acesso ao objeto da exceção e à sua mensagem, que pode ser exibida em uma f-string. Se a exceção não for compatível com ValueError, ela continuará se propagando; nesse caso, o código após a estrutura não será alcançado por esse fluxo.
Complete o tipo da exceção para tratar a conversão e acessar sua mensagem:
try:
idade = int(texto)
except ____ as erro:
print(f"idade inválida: {erro}")Considere o código abaixo e ordene somente as mensagens que serão exibidas:
def converter(texto):
print("B")
return int(texto)
print("A")
try:
valor = converter("x")
print("C")
except ValueError as erro:
print("D")
print("E")
Passo 3 de 8
Organize capturas alternativas de acordo com a resposta necessária para cada tipo de falha e preserve a propagação de erros não previstos.
Quando cada tipo de falha exige uma resposta diferente, use cláusulas except separadas. Neste exemplo, uma conversão inválida produz ValueError, enquanto a divisão por zero produz ZeroDivisionError.
Observe que cada cláusula produz uma mensagem adequada ao tipo de falha.
def calcular_razao(texto_total, texto_partes):
try:
total = int(texto_total)
partes = int(texto_partes)
return total / partes
except ValueError as erro:
return f"Conversão inválida: {erro}"
except ZeroDivisionError as erro:
return f"Divisão por zero: {erro}"
print(calcular_razao("dez", "2"))
print(calcular_razao("10", "0"))
print(calcular_razao("10", "2"))Quando uma exceção sai do try, o Python examina as cláusulas except de cima para baixo. Ele executa somente a primeira compatível e não continua procurando outros tratamentos. Se nenhuma for compatível, a exceção continua se propagando.
O fluxo pode chegar ao tratamento de conversão, ao tratamento de divisão por zero ou sair da estrutura sem tratamento.

As duas falhas previstas são tratadas; TypeError não corresponde a nenhuma das capturas declaradas.
Dica
Mesmo com várias cláusulas compatíveis possíveis, apenas a primeira encontrada seria executada. Neste exemplo, ValueError e ZeroDivisionError são distintos, então cada um chega diretamente ao seu tratamento específico.
Se as falhas devem receber exatamente o mesmo tratamento, coloque os tipos em uma tupla. O agrupamento deve representar uma decisão do programa, não apenas uma tentativa de reduzir linhas.
Agora as duas falhas previstas recebem a mesma resposta.
def calcular_razao(texto_total, texto_partes):
try:
total = int(texto_total)
partes = int(texto_partes)
return total / partes
except (ValueError, ZeroDivisionError) as erro:
return f"Não foi possível calcular: {erro}"
print(calcular_razao("dez", "2"))
print(calcular_razao("10", "0"))Atenção
A chamada calcular_razao(None, "2") produz TypeError em int(None). Como esse tipo não aparece na tupla, a falha permanece visível e continua se propagando.
Considere a versão com cláusulas separadas. Associe cada chamada ao seu destino.
Toque em um item e depois no par correspondente.
O programa deve pedir a correção do texto quando ocorrer ValueError, mas informar que o divisor não pode ser zero quando ocorrer ZeroDivisionError. Qual organização atende melhor ao requisito?

Passo 4 de 8
Use else para executar somente as ações que dependem da conclusão bem-sucedida do bloco try e reconheça que falhas surgidas no próprio else continuam se propagando.
O bloco else associado a try é executado somente quando o try chega ao fim sem produzir uma exceção. Se uma exceção surgir no try, o fluxo procura um except compatível e não passa pelo else — mesmo quando a exceção é tratada.
Isso permite deixar no try apenas a operação sujeita à falha esperada e mover para o else as ações que dependem do resultado bem-sucedido.
Execute o código e compare as duas chamadas.
def mostrar_metade(texto):
try:
numero = int(texto)
except ValueError as erro:
print(f"Não foi possível converter: {erro}")
else:
metade = numero / 2
print(f"Metade: {metade}")
mostrar_metade("8")
mostrar_metade("oito")Há três caminhos importantes:
try terminar sem exceção, o fluxo segue para o else.try produzir uma exceção compatível, o fluxo segue para o except e ignora o else.try terminar com sucesso, mas uma operação no else falhar, essa nova exceção sai da estrutura e continua se propagando.
O except associado à estrutura examina falhas do try, não as falhas produzidas depois, dentro do else.
No código abaixo, int("0") termina normalmente, então o else é iniciado. A divisão por zero acontece dentro dele. Como os except desta estrutura tratam exceções produzidas no try, o ZeroDivisionError não é capturado pelo except ValueError e continua se propagando.
Ao executar, a primeira mensagem aparece antes do traceback.
def calcular_inverso(texto):
try:
numero = int(texto)
except ValueError as erro:
print(f"Entrada inválida: {erro}")
else:
print("Conversão concluída")
inverso = 1 / numero
print(f"Inverso: {inverso}")
calcular_inverso("0")Dica
Manter apenas a conversão no try deixa claro que o tratamento foi planejado para uma falha dessa conversão. O processamento que depende do número convertido fica no else, e suas próprias falhas não são confundidas com a falha esperada.
def procurar(texto):
try:
numero = int(texto)
except ValueError:
print("Entrada inválida")
else:
print("Conversão concluída")
posicao = ["10", "20"].index(texto)
print(numero, posicao)
procurar("30")O que acontece na chamada procurar("30")?

Passo 5 de 8
Preveja quando o bloco finally é executado e diferencie encerramento da estrutura de tratamento ou recuperação de uma exceção.
O bloco finally é executado quando o fluxo sai da estrutura try, seja após o sucesso, após um except ou enquanto uma exceção não tratada está se propagando.
Nos caminhos mais comuns:
try → else → finally → depois da estrutura;try → except → finally → depois da estrutura;try → finally → propagação.Executar finally não significa que o erro foi tratado. Se ainda houver uma exceção pendente e o finally terminar normalmente, ela continuará se propagando.
Observe que todos os caminhos chegam ao bloco dourado. Somente os caminhos sem uma exceção pendente seguem para a continuação normal.

Azul representa try, verde representa else, laranja representa except e dourado representa finally. A seta vermelha indica a propagação de uma exceção pendente.
A função abaixo registra a passagem pelos blocos em uma lista. Execute cada chamada separadamente, pois o terceiro cenário termina com uma exceção não tratada.
def executar(texto, divisor):
eventos = []
try:
eventos.append("try")
numero = int(texto)
except ValueError as erro:
eventos.append(f"except: {erro}")
else:
eventos.append("else")
resultado = 10 / divisor
eventos.append(f"resultado: {resultado}")
finally:
eventos.append("finally")
print(eventos)
print("depois da estrutura")
# Execute uma chamada por vez:
executar("5", 2) # sucesso
# executar("abc", 2) # ValueError tratada
# executar("5", 0) # ZeroDivisionError no elseDica
Com "5" e 2, passam try, else e finally, e a execução continua. Com "abc", passam try, except e finally, e também há continuação. Com divisor zero, a falha surge no else: finally ainda imprime a lista, mas depois da estrutura não aparece porque ZeroDivisionError continua se propagando.
Uma nova exceção pode surgir durante um except, assim como pode surgir no else. Nesses casos, finally ainda é executado antes da propagação. Ele realiza sua ação de encerramento, mas não recupera o programa automaticamente.
def falhar_durante_tratamento():
eventos = []
try:
int("inválido")
except ValueError:
eventos.append("except")
10 / 0
finally:
eventos.append("finally")
print(eventos)
print("depois da estrutura")
falhar_durante_tratamento()Atenção
Nesse exemplo, finally imprime ['except', 'finally']. Em seguida, ZeroDivisionError permanece visível no traceback, e a mensagem depois da estrutura não é executada.
Coloque em ordem os acontecimentos de executar("5", 0).
Qual sequência descreve executar("abc", 2)?

Passo 6 de 8
Reconheça como um return em finally pode substituir outro retorno ou ocultar uma exceção, e organize a função para preservar seu resultado real.
Quando o Python encontra return dentro de try, ele prepara o valor de retorno, mas executa finally antes de sair da função. Como o try não chegou normalmente ao fim, o bloco else não é executado.
Se o próprio finally executar outro return, esse novo retorno substituirá o anterior.
Execute o código e observe que a mensagem do else não aparece.
def obter_pontuacao():
try:
return 10
else:
print("Try concluído sem retorno antecipado")
finally:
print("Encerrando cálculo")
return 99
print(obter_pontuacao())
# Saída:
# Encerrando cálculo
# 99Atenção
O valor 10 estava pronto para ser devolvido, mas o return 99 do finally tomou seu lugar. Isso torna o resultado da função diferente daquele indicado pelo fluxo principal.
Se houver uma exceção pendente, o finally ainda será executado. Porém, um return dentro dele encerra a função com um valor e suprime a exceção. A ação de encerramento aconteceu, mas a falha inesperadamente deixou de se propagar.
Compare os caminhos: um encerramento normal permite que o retorno ou a exceção pendente continue; um novo retorno criado no finally ocupa a saída e descarta o que estava pendente.

O finally deve executar o encerramento sem trocar o retorno nem apagar a exceção pendente.
int("abc") produz ValueError, mas o return de finally oculta essa falha.
def converter(texto):
try:
return int(texto)
finally:
print("Encerrando conversão")
return 0
print(converter("abc"))
# Saída:
# Encerrando conversão
# 0Mantenha no finally somente as ações que devem ocorrer em qualquer caminho. O tratamento específico, o processamento de sucesso e a decisão de retorno ficam fora dele.
Agora o encerramento sempre ocorre, mas não altera a decisão tomada pelos outros blocos.
def dobrar_texto_numerico(texto):
try:
numero = int(texto)
except ValueError as erro:
resultado = f"Entrada inválida: {erro}"
else:
resultado = numero * 2
finally:
print("Encerrando conversão")
return resultado
print(dobrar_texto_numerico("21"))
print(dobrar_texto_numerico("abc"))Dica
Use finally para encerramento, não para escolher o resultado da função. Sem return nesse bloco, um retorno pendente permanece válido e uma exceção pendente continua visível.
Analise as duas funções antes de responder.
def primeira():
try:
return 8
finally:
return 12
def segunda():
try:
return int("x")
finally:
return -1
print(primeira())
print(segunda())O que cada chamada imprime? Por que a segunda função não exibe um traceback? Indique uma correção que mantenha uma ação de encerramento em finally sem alterar retornos nem ocultar exceções.
Escreva pelo menos 100 caracteres (0/100).

Passo 7 de 8
Reduza o escopo do try para tratar apenas falhas previstas pelo contexto e manter erros inesperados visíveis.
Uma exceção é esperada quando faz parte das falhas previstas para uma operação específica. Por exemplo, ao converter um texto fornecido pelo usuário com int, um ValueError pode ser uma entrada que o programa sabe tratar. Mas um ValueError em outra operação pode indicar um defeito.
Por isso, não basta perguntar “qual é o tipo da exceção?”. Também é necessário perguntar “qual operação poderia produzir esse erro e por que ele é esperado aqui?”.
O try deve envolver somente a operação cuja falha foi prevista. Operações posteriores ficam fora dessa fronteira para que seus erros não sejam confundidos com a falha esperada.

À esquerda, a captura ampla mistura falhas diferentes. À direita, somente a conversão esperada está dentro do try.
A conversão pode falhar com ValueError, mas list.index também produz esse tipo quando não encontra o item. O código abaixo transforma até o erro de digitação interno em uma mensagem sobre a entrada.
def preparar_pedido(texto_quantidade):
etapas = ["recebido", "pago", "enviado"]
try:
quantidade = int(texto_quantidade)
posicao = etapas.index("enviadoo")
except ValueError as erro:
return f"Entrada inválida: {erro}"
else:
return quantidade, posicao
print(preparar_pedido("12"))Agora, somente a conversão está no try. Uma entrada como "doze" recebe o tratamento planejado. Com "12", o erro de digitação em index permanece visível porque exceções produzidas no else não são capturadas pelo except associado.
def preparar_pedido(texto_quantidade):
etapas = ["recebido", "pago", "enviado"]
try:
quantidade = int(texto_quantidade)
except ValueError as erro:
return f"Entrada inválida: {erro}"
else:
posicao = etapas.index("enviadoo")
return quantidade, posicao
print(preparar_pedido("12"))Dica
Deixar uma falha inesperada se propagar preserva o traceback e evita devolver uma mensagem ou um valor que pareça indicar funcionamento normal. Corrigir o defeito é melhor do que classificá-lo incorretamente como uma entrada inválida.
except Exception captura muitos erros que podem não fazer parte da recuperação planejada, como falhas de índice, operações com tipos incompatíveis ou divisões por zero. Se todos virarem None, 0 ou uma mensagem genérica, defeitos podem passar despercebidos.
Um except sem tipo tem alcance ainda maior e pode interceptar inclusive uma interrupção feita pelo usuário pelo teclado. Para uma falha conhecida, prefira o tipo específico e um try restrito à operação correspondente.
Atenção
Evite padrões como except Exception: return 0 ou except: pass. Se 0 ou a continuação silenciosa parecerem resultados válidos, o restante do programa poderá trabalhar com uma informação incorreta sem revelar a causa original.
A conversão de texto_indice é a única falha esperada neste cenário. As operações com a lista devem manter visíveis falhas não previstas.
def calcular_parcela(texto_indice, precos):
try:
indice = int(texto_indice)
preco = precos[indice]
parcela = preco / indice
except Exception:
return 0
else:
return parcelaRefatore a função para tratar especificamente a falha de conversão. Coloque no else as operações que dependem do índice convertido e explique por que as demais exceções não devem ser transformadas em 0.
Escreva pelo menos 80 caracteres (0/80).

Passo 8 de 8
Refatore um programa em memória, execute quatro cenários separadamente e interprete a falha que deve continuar visível.
Copie o script abaixo para um arquivo .py no seu computador. Ele calcula uma razão usando apenas dados em memória, mas apresenta três problemas: o try inclui processamento posterior, except Exception captura também a falha inesperada e há um return dentro de finally.
Refatore a função para:
try somente as conversões e a divisão;ValueError e ZeroDivisionError separadamente;as erro;fator e a mensagem de sucesso no else;finally, sem executar return nele.Altere somente a função calcular_razao. Para cada execução, escolha um dos quatro nomes em CENARIO.
def calcular_razao(texto_numerador, texto_denominador, fator):
eventos = []
try:
numerador = int(texto_numerador)
denominador = int(texto_denominador)
resultado = numerador / denominador
ajustado = resultado * fator
except Exception as erro:
eventos.append(f"falha: {erro}")
else:
eventos.append(f"resultado: {ajustado:.2f}")
finally:
eventos.append("encerramento")
print(" | ".join(eventos))
return eventos
CENARIO = "sucesso"
casos = {
"sucesso": ("12", "3", 2),
"conversao": ("doze", "3", 2),
"divisao_zero": ("12", "0", 2),
"inesperada": ("12", "3", "dobro"),
}
texto_a, texto_b, fator = casos[CENARIO]
calcular_razao(texto_a, texto_b, fator)Atenção
Troque o valor de CENARIO e reinicie o script em cada teste. A falha inesperada deve encerrar sua própria execução com um traceback; por isso, não dependa de uma única execução para observar todos os casos.
Nesta versão, somente as falhas esperadas das conversões e da divisão são capturadas. O processamento que depende do resultado fica no else. Se esse processamento falhar, os except associados ao mesmo try não interceptam a nova exceção.
Substitua a função inicial por esta versão e mantenha o restante do script.
def calcular_razao(texto_numerador, texto_denominador, fator):
eventos = []
try:
numerador = int(texto_numerador)
denominador = int(texto_denominador)
resultado = numerador / denominador
except ValueError as erro:
eventos.append(f"conversão inválida: {erro}")
except ZeroDivisionError as erro:
eventos.append(f"divisão inválida: {erro}")
else:
ajustado = resultado * fator
eventos.append(f"resultado: {ajustado:.2f}")
finally:
eventos.append("encerramento")
print(" | ".join(eventos))Observe que todos os caminhos passam pelo encerramento, mas somente três terminam normalmente.

O finally registra o encerramento, mas não transforma a falha inesperada em sucesso.
Execute separadamente sucesso, conversao, divisao_zero e inesperada.
No sucesso, procure resultado: 8.00 | encerramento. Nos dois erros esperados, confirme a mensagem específica seguida de encerramento. No cenário inesperado, o finally imprime encerramento, mas depois aparece um traceback de TypeError.
Leia esse traceback de fora para dentro: localize primeiro a chamada de calcular_razao no código de nível superior e depois a multiplicação resultado * fator dentro da função. A última linha informa o tipo e a mensagem da falha.
Quais blocos foram executados em cada cenário? Por que ValueError e ZeroDivisionError foram tratados, enquanto TypeError permaneceu visível? Relacione também os quadros do traceback às chamadas do programa.
Escreva pelo menos 180 caracteres (0/180).
Resumo
Use estes critérios ao decidir como tratar uma falha esperada.
try apenas as operações cujas falhas você planejou tratar.as erro quando precisar apresentar ou registrar a mensagem.else as ações que dependem do sucesso completo do try.finally para ações de encerramento, não para ocultar exceções nem substituir resultados com return.Parabéns! Você concluiu: Tratar exceções com try, except, else e finally
100 XP
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks