Módulo 12 - Exceções, logging e robustez

Uma hierarquia de exceções do seu domínio

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

Velocidade

O que você vai aprender

  • Criar uma classe base de exceção para o seu domínio.
  • Derivar exceções específicas dessa base, formando uma hierarquia.
  • Capturar erros no nível de precisão certo com except.
  • Anexar dados úteis à exceção para quem for tratá-la.

Por que uma família inteira de exceções

Uma exceção própria isolada já ajuda, mas o salto de engenharia é pensar em família. A ideia é ter uma classe base que represente qualquer erro do seu domínio, digamos um sistema de pagamentos, e derivar dela exceções específicas para cada tipo de falha: saldo insuficiente, cartão recusado, valor inválido. Com essa árvore montada, quem usa o seu código escolhe a granularidade do tratamento. Pode capturar a base e tratar qualquer problema de pagamento de uma vez, ou capturar apenas o cartão recusado para pedir outro método.

class ErroPagamento(Exception):
    """Base de todos os erros do dominio de pagamentos."""

class SaldoInsuficiente(ErroPagamento):
    pass

class CartaoRecusado(ErroPagamento):
    pass

class ValorInvalido(ErroPagamento):
    pass

# Quem trata escolhe a precisao:
try:
    pass  # ... alguma operacao de pagamento ...
except CartaoRecusado:
    print("tente outro cartao")   # so este caso
except ErroPagamento as e:
    print("falha no pagamento:", e)  # qualquer outro erro do dominio

Uma base do domínio e folhas específicas: o except pega o nível que quiser.

Repare na ordem dos except: o mais específico, CartaoRecusado, vem antes do mais geral, ErroPagamento. O Python testa os except de cima para baixo e usa o primeiro que casa, então colocar a base primeiro capturaria tudo e o bloco específico nunca rodaria. Essa hierarquia também protege quem consome o seu código: mesmo que você acrescente novas exceções no futuro, contanto que herdem de ErroPagamento, o except da base continua pegando todas, sem quebrar código existente.

Exceções que carregam dados

Uma exceção não precisa ser só uma mensagem de texto. Ela é um objeto, e pode carregar dados que ajudam quem for tratá-la. Uma falha de saldo insuficiente fica muito mais útil se levar consigo o valor pedido e o saldo disponível, para que o tratamento calcule quanto falta ou registre o caso com precisão. Basta escrever um __init__ na exceção, guardar os atributos e chamar o __init__ da base com uma mensagem legível.

class SaldoInsuficiente(ErroPagamento):
    def __init__(self, pedido, saldo):
        self.pedido = pedido
        self.saldo = saldo
        self.falta = pedido - saldo
        super().__init__(
            f"pedido de R$ {pedido} com saldo de R$ {saldo} (faltam R$ {self.falta})"
        )

def sacar(saldo, valor):
    if valor > saldo:
        raise SaldoInsuficiente(valor, saldo)
    return saldo - valor

try:
    sacar(100, 150)
except SaldoInsuficiente as e:
    print("mensagem:", e)       # texto pronto
    print("faltam:", e.falta)   # dado estruturado: 50

A exceção guarda pedido, saldo e falta: o tratamento acessa dados, não só texto.

Capturar no nível certo

Ter a hierarquia é metade do trabalho; a outra metade é capturar no nível certo. Um erro comum de iniciante é escrever except Exception para tudo, ou pior, um except sem tipo nenhum, que engole qualquer falha, inclusive erros de programação como um nome digitado errado. A regra é capturar o mais específico que você sabe tratar e deixar o resto subir. Se você só sabe lidar com cartão recusado, capture apenas CartaoRecusado; deixe os outros erros seguirem para quem souber tratá-los, ou para o topo do programa.

Captura ampla demais

  • except: ou except Exception: para tudo
  • Esconde bugs reais junto com erros esperados
  • Dificulta descobrir a causa de uma falha
  • O programa continua num estado incerto

Captura no nível certo

  • Captura só o que sabe tratar, como CartaoRecusado
  • Deixa erros inesperados subirem e aparecerem
  • A causa fica clara, no lugar certo
  • Falhas de verdade não passam despercebidas

Essa disciplina se conecta com a robustez do módulo inteiro. Capturar de menos deixa o programa quebrar sem tratamento; capturar de mais esconde defeitos e cria falhas silenciosas, que são as piores de depurar. A hierarquia bem desenhada dá a você as ferramentas para acertar o meio-termo: capture a base quando quiser tratar qualquer erro do domínio, capture uma folha quando quiser reagir a um caso específico, e nunca capture erros que você não sabe tratar só para calar o programa.

Teste rápido

Por que ordenar os blocos except do mais específico para o mais geral?

Perguntas frequentes

De qual classe minha exceção base deve herdar?
De Exception. Ela é a base pensada para erros que o seu programa pode tratar. Evite herdar de BaseException, que é o topo reservado para exceções de controle como KeyboardInterrupt e SystemExit, que normalmente não devem ser capturadas por engano.
Vale a pena criar exceções próprias em um programa pequeno?
Em scripts muito curtos, as exceções embutidas costumam bastar. À medida que o código cresce e vira uma biblioteca ou aplicação, uma hierarquia própria compensa: ela documenta as falhas possíveis e dá a quem usa o seu código o controle de capturar o que quiser.
Posso guardar qualquer dado dentro de uma exceção?
Sim, uma exceção é um objeto comum e pode ter os atributos que você quiser. É boa prática guardar dados que ajudem o tratamento, como valores envolvidos na falha. Só evite guardar informações sensíveis que possam vazar em logs, como senhas.
Qual a diferença entre capturar Exception e capturar uma folha?
Capturar Exception ou a base do domínio pega qualquer erro daquele grupo, útil para um tratamento genérico no topo. Capturar uma folha, como CartaoRecusado, reage a um caso específico. Use a folha quando souber exatamente o que fazer com aquele erro.
É errado usar except sem especificar o tipo?
Quase sempre, sim. Um except sem tipo captura tudo, inclusive erros de programação e sinais de interrupção, escondendo bugs e criando falhas silenciosas. Prefira capturar o tipo específico que você sabe tratar e deixe o resto subir para ser visto.

Fontes

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