Módulo 9 - Erros e exceções: nível avançado

Encadeamento e boas práticas

11 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026

O que você vai aprender

  • Evitar o except puro que engole todos os erros em silêncio.
  • Capturar sempre o tipo mais específico que você sabe tratar.
  • Escrever mensagens de erro que ajudam a depurar.
  • Conhecer o raise from para preservar a causa original.

O que não fazer com exceções

O pior hábito com exceções é o except vazio que não faz nada, às vezes com um pass dentro. O programa realmente para de quebrar, mas por um motivo terrível: ele passou a ignorar todos os erros, inclusive os que apontam bugs de verdade. Um dia o cálculo dá resultado errado, ninguém entende por quê, e a resposta é que um except mudo estava engolindo a exceção que explicava tudo. Errar em silêncio é pior que quebrar, porque a quebra ao menos avisa. Se você não sabe tratar um erro, é melhor deixá-lo aparecer.

# ANTIPADRÃO: engole tudo em silêncio
try:
    total = calcular(pedido)
except:
    pass  # e agora ninguém sabe que algo falhou

# MELHOR: trate o que você espera, deixe o resto subir
try:
    total = calcular(pedido)
except ValueError as erro:
    print("Pedido inválido:", erro)

O except vazio com pass esconde qualquer falha; o específico trata só o previsto.

A regra de ouro é capturar o mais específico que você sabe tratar. Se a função pode falhar por ValueError, escreva except ValueError. Se pode falhar de duas formas, escreva os dois except. Não estenda a captura para tipos que você não entende só por precaução, porque isso volta a esconder o inesperado. Pense assim: cada except é uma promessa de que você sabe o que fazer com aquele erro. Não faça promessas que não pode cumprir.

Mensagens úteis e o raise from

Uma boa mensagem de erro economiza minutos ou horas de investigação. Compare "erro ao processar" com "data de nascimento inválida: 32/13/2020". A segunda diz o que falhou e mostra o dado problemático. Sempre que levantar uma exceção, inclua contexto: qual regra foi violada, qual valor chegou, o que era esperado. Essa mensagem viaja com a exceção e aparece no traceback ou na variável capturada com as, então o esforço de escrevê-la bem se paga toda vez que o erro acontece.

Às vezes você captura um erro de baixo nível e quer levantar outro, mais adequado ao seu programa. Ao fazer isso, é fácil perder a pista da causa original. O raise from resolve: ele levanta a nova exceção mantendo o vínculo com a que a provocou. No traceback, o Python mostra as duas e explica que uma foi a causa direta da outra. Assim, quem depura vê tanto o erro que você escolheu expor quanto a falha técnica que o gerou, sem ter que adivinhar.

class ConfiguracaoInvalidaError(Exception):
    pass


def ler_porta(texto):
    try:
        return int(texto)
    except ValueError as erro:
        raise ConfiguracaoInvalidaError(f"Porta inválida: {texto!r}") from erro

ler_porta("abc")

# Traceback (most recent call last):
#   ... ValueError: invalid literal for int() with base 10: 'abc'
#
# The above exception was the direct cause of the following exception:
#   ... ConfiguracaoInvalidaError: Porta inválida: 'abc'

O raise from liga a exceção nova à original; o traceback mostra as duas encadeadas.

Fixando as boas práticas

Boas práticas de exceção têm um fio comum: não esconder a verdade. O except vazio esconde; o tipo específico revela. A mensagem pobre esconde; a mensagem com contexto revela. Trocar uma exceção por outra sem raise from esconde a causa; com raise from, a causa fica registrada. Programar defensivamente não é abafar erros, é lidar com eles de forma que o problema, quando aparecer, seja fácil de entender e corrigir. Com esses hábitos firmes, você está pronto para a prática do módulo: uma função de saque robusta, do jeito certo.

Teste rápido

Por que um except vazio com pass é considerado um antipadrão?

Perguntas frequentes

Quando faz sentido capturar Exception de forma ampla?
Em pontos de fronteira bem definidos, como o laço principal de um servidor que precisa registrar qualquer falha e continuar. Mesmo nesses casos, o certo é registrar a exceção, e não ignorá-la. No meio da lógica de negócio, prefira sempre o tipo específico.
O que exatamente o raise from faz?
Levanta uma nova exceção mantendo o vínculo com a original que a causou. O traceback passa a mostrar as duas, com a frase indicando que uma foi a causa direta da outra. Isso preserva a pista técnica ao mesmo tempo em que expõe um erro mais adequado ao seu programa.
Devo sempre transformar exceções embutidas nas minhas?
Não. Só converta quando a sua exceção comunica melhor o problema para quem chama, como transformar um ValueError técnico em ConfiguracaoInvalidaError. Se a embutida já é clara e adequada, deixe-a subir como está. Conversão sem propósito só adiciona ruído.
Como escrevo uma mensagem de erro realmente útil?
Diga o que deu errado, qual regra foi violada e mostre o valor envolvido. Prefira "idade inválida: -3" a "entrada inválida". Use f-strings para incluir os dados. O leitor da mensagem, muitas vezes você no futuro, agradece cada detalhe que evita adivinhação.
É errado usar try e except em vez de um if?
Depende. Para condições que você consegue checar antes, como validar um intervalo, um if costuma ser mais claro. Para operações que só revelam o problema ao serem executadas, como abrir um arquivo, o try e except é o caminho. Use a ferramenta que deixa a intenção mais evidente.
Preciso decorar todos os tipos de exceção embutidos?
Não. Você memoriza os mais comuns com a prática, como ValueError, TypeError, KeyError e FileNotFoundError. Para o resto, o traceback mostra o tipo e a documentação oficial lista todos, com a hierarquia entre eles. Saber consultar vale mais que decorar.

Fontes

Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.