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

Criando exceções próprias

11 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 de exceção herdando de Exception.
  • Nomear a exceção de forma que ela conte a regra do seu programa.
  • Levantar e capturar a sua própria exceção com raise e except.
  • Decidir quando vale a pena criar uma exceção em vez de reusar uma embutida.

Por que criar a sua própria exceção

As exceções embutidas são ótimas, mas genéricas. ValueError diz que um valor é inválido, e nada mais. Só que o seu programa tem regras próprias. Uma conta bancária pode ter a regra "não sacar mais do que o saldo". Você poderia levantar um ValueError para isso, mas o nome não conta a história. Se, em vez disso, você levanta um SaldoInsuficienteError, qualquer pessoa que leia o código, ou que precise tratar esse caso, entende de imediato o que aconteceu. O nome da exceção vira documentação viva da regra de negócio.

class SaldoInsuficienteError(Exception):
    """Levantada quando um saque excede o saldo disponível."""


def sacar(saldo, valor):
    if valor > saldo:
        raise SaldoInsuficienteError(f"Saque de {valor} maior que o saldo de {saldo}")
    return saldo - valor

print(sacar(100, 30))   # 70
print(sacar(100, 150))  # levanta SaldoInsuficienteError

Uma classe que herda de Exception já é uma exceção completa; o docstring explica quando ela é levantada.

Repare como a definição é curta. A classe SaldoInsuficienteError herda de Exception e o corpo é apenas um docstring que explica quando ela acontece. Poderia ser um simples pass. Isso basta porque a herança faz o trabalho pesado: aceitar a mensagem, guardar os argumentos, aparecer no traceback com o nome certo. Você só está dando um rótulo específico a um erro específico. Levantá-la é igual a levantar qualquer exceção: raise SaldoInsuficienteError com a mensagem.

Capturar a sua exceção com clareza

A grande vantagem aparece na hora de tratar. Com um nome próprio, quem chama a função consegue reagir de forma específica a esse caso, sem confundir com outros erros de valor. Um except SaldoInsuficienteError pega exatamente essa situação e mais nenhuma. Se você tivesse usado ValueError, um saque acima do saldo se misturaria com qualquer outro valor inválido, e você não conseguiria dar mensagens diferentes para problemas diferentes. A exceção própria separa as águas.

saldo = 100

try:
    saldo = sacar(saldo, 150)
except SaldoInsuficienteError as erro:
    print("Operação recusada:", erro)
else:
    print("Novo saldo:", saldo)

# Saída:
# Operação recusada: Saque de 150 maior que o saldo de 100

O as erro captura o objeto da exceção; imprimi-lo mostra a mensagem que você passou ao raise.

O trecho except SaldoInsuficienteError as erro guarda o objeto da exceção na variável erro. Imprimir esse objeto mostra a mensagem que você definiu no raise. É por isso que caprichar na mensagem compensa: ela chega inteira até quem trata o erro. Você também pode organizar várias exceções do seu programa criando uma classe base, por exemplo class ErroDaConta(Exception), e fazendo SaldoInsuficienteError e outras herdarem dela. Assim, um except ErroDaConta captura qualquer erro daquela família de uma vez, quando essa for a intenção.

Reusar ValueError

  • Nome genérico, não conta a regra
  • Mistura com outros valores inválidos
  • except pega mais do que você queria
  • Bom para validações simples e locais

Criar SaldoInsuficienteError

  • Nome fala a linguagem do domínio
  • Isola exatamente esse caso
  • except trata só essa situação
  • Bom quando quem chama precisa distinguir

Fixando as exceções próprias

Criar uma exceção é barato: uma classe curta que herda de Exception. O valor está no nome e na clareza que ele traz. Mas não crie por criar. Se o erro é local, simples e ninguém precisa distinguir, uma embutida como ValueError basta. A exceção própria compensa quando o problema faz parte das regras do seu programa e quem chama precisa tratá-lo de forma específica, como o saque acima do saldo. Na próxima aula você junta tudo em boas práticas, e no fim do módulo transforma esse SaldoInsuficienteError numa função de saque completa.

Teste rápido

Qual é o jeito correto de definir uma exceção própria no Python?

Perguntas frequentes

De qual classe minha exceção deve herdar?
De Exception, na quase totalidade dos casos. Ela é a base recomendada para erros que o seu programa levanta e trata. Evite herdar de BaseException, que é reservada para casos especiais do próprio Python, como a interrupção pelo teclado.
Preciso escrever algum código dentro da classe?
Não. Um corpo com apenas pass ou um docstring já cria uma exceção completa, porque a herança de Exception fornece tudo. Você só escreve mais quando quer guardar dados extras, como o valor do saque, criando um método de inicialização próprio.
Como sei se vale a pena criar uma exceção própria?
Pergunte se quem chama a função vai precisar distinguir esse erro dos demais. Se sim, um nome próprio ajuda a tratar o caso separadamente. Se o erro é local e simples, uma exceção embutida como ValueError costuma bastar, sem inventar classes novas.
Por que o nome termina em Error?
É uma convenção do Python. As exceções embutidas seguem esse padrão, como ValueError e KeyError. Terminar o nome da sua em Error deixa claro, só de bater o olho, que aquela classe é uma exceção, e não um dado ou uma função comum.
Posso ter uma família de exceções relacionadas?
Pode e é uma boa prática. Crie uma classe base, como ErroDaConta, e faça as específicas herdarem dela: SaldoInsuficienteError, ContaBloqueadaError. Assim, um except ErroDaConta captura qualquer erro da família, e um except mais específico trata um caso isolado.
Exceção própria deixa o programa mais lento?
Não de forma perceptível. Definir a classe custa quase nada, e levantar uma exceção própria tem o mesmo custo de levantar uma embutida. O ganho de clareza compensa muito qualquer custo, que na prática é irrelevante para o desempenho.

Fontes

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