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
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.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: Uma hierarquia de exceções do seu domínio.
Os objetivos desta aula. 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.
Veja o essencial, parte por parte.
Por que uma família inteira de exceções. Comece por uma classe base do seu domínio, herdando de Exception.
Exceções que carregam dados. Herde de Exception, nunca de BaseException, que é reservada para casos como KeyboardInterrupt.
Capturar no nível certo. Ter a hierarquia é metade do trabalho; a outra metade é capturar no nível certo.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
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 dominioUma 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: 50A 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.