
Programação Orientada a Objetos
Raise e exceções customizadas
Criando seus proprios erros
Professor Vitor Hugo · 2º ano EMI
Recap
Retomando o tratamento de exceções
try delimita um trecho no qual uma exceção pode acontecer.
except define como tratar um tipo específico de exceção.
else executa somente quando nenhuma exceção ocorre no try.
finally executa ao final, com ou sem exceção.
Essas estruturas não impedem todos os erros — elas permitem que o programa responda às exceções previstas.
Questão da aula: como sinalizar uma situação inválida que depende das regras do nosso próprio programa?
PROGRAMAÇÃO ORIENTADA A OBJETOS
Situação-problema
Uma situação que o Python aceita
app.py
nota = float(input("Digite sua nota: "))
if nota >= 6:
print("Aprovado")
else:
print("Reprovado")se o usuário digitar 15, a conversão para float funciona;
o valor é numericamente válido, mas não representa uma nota válida para o sistema;
Python conhece as regras da linguagem, mas não conhece as regras da escola.
Como a função pode avisar que recebeu uma nota fora do intervalo permitido?
PROGRAMAÇÃO ORIENTADA A OBJETOS
Conceito
Exceções da linguagem e regras do sistema
Detectadas pela linguagem
ZeroDivisionError: divisão por zero;
ValueError: valor inadequado para a operação;
KeyError: chave inexistente.
Dependem do nosso sistema
nota fora do intervalo de 0 a 10;
saque maior que o saldo disponível;
venda maior que a quantidade em estoque;
idade negativa.
Quando uma regra impede a conclusão da operação, o código pode sinalizar o problema usando raise.
PROGRAMAÇÃO ORIENTADA A OBJETOS
raise
Lançando uma exceção com raise
app.py
nota = 15
if nota < 0 or nota > 10:
raise ValueError(
"A nota precisa estar entre 0 e 10."
)
print("Nota registrada:", nota)Leitura da instrução
ValueError é a classe da exceção;
os parênteses criam um objeto dessa classe;
o texto explica o motivo do problema;
raise lança o objeto no fluxo de tratamento.
PROGRAMAÇÃO ORIENTADA A OBJETOS
raise
Sem um except compatível
Saída
Traceback (most recent call last):
...
ValueError: A nota precisa estar entre 0 e 10.
A instrução print não é executada: o fluxo normal para no ponto do raise.
Sem um except compatível, o Python exibe o traceback e encerra a execução.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Fluxo de execução
O fluxo depois do raise
app.py
def registrar_nota(nota):
print("Iniciando o registro")
if not 0 <= nota <= 10:
raise ValueError("Nota inválida.")
print("Registro concluído")Ao executar registrar_nota(15)
1A função imprime "Iniciando o registro".
2A condição identifica que 15 está fora do intervalo.
3raise lança um ValueError.
4A função para imediatamente.
5Python procura um except compatível nas chamadas anteriores.
6Sem tratador, exibe o traceback e encerra.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Papéis
Quem detecta e quem trata
regras.py
def registrar_nota(nota):
if not 0 <= nota <= 10:
raise ValueError(
"A nota precisa estar entre 0 e 10."
)
return notamain.py
try:
nota = registrar_nota(15)
print("Nota registrada:", nota)
except ValueError as erro:
print("Não foi possível registrar:", erro)PROGRAMAÇÃO ORIENTADA A OBJETOS
Papéis
Detectar não é o mesmo que tratar
A função conhece a regra e detecta o problema; o chamador conhece o contexto e decide como responder.
except ValueError as erro captura o objeto lançado — erro guarda a mensagem.
O chamador poderia mostrar uma mensagem, pedir outro valor, registrar o problema ou cancelar a operação.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Conceito
return e raise têm papéis diferentes
return
a função concluiu o trabalho normalmente;
devolve o resultado esperado.
raise
a função não concluiu o trabalho;
transfere o controle a um tratador.
app.py
def calcular_media(notas):
if len(notas) == 0:
raise ValueError("A lista está vazia.")
return sum(notas) / len(notas)Para uma lista vazia não existe média a calcular. Retornar 0 esconderia a diferença entre "a média foi zero" e "não foi possível calcular".
PROGRAMAÇÃO ORIENTADA A OBJETOS
Prática 1
Prática 1
Crie a função validar_idade(idade)
idade negativa é considerada inválida;
idade inválida → a função lança ValueError com mensagem explicativa;
idade válida → a função devolve o valor recebido;
o código chamador trata a exceção e informa que o cadastro não foi realizado.
Casos de teste
idade 16a função devolve 16
idade 0a função devolve 0
idade -5o programa trata ValueError
PROGRAMAÇÃO ORIENTADA A OBJETOS
Critério
Quando usar raise
raise faz sentido quando a função não cumpre a responsabilidade do seu contrato:
calcular uma média sem receber notas;
retirar do estoque uma quantidade inexistente;
concluir um saque sem saldo suficiente;
cadastrar um valor que viola uma regra obrigatória.
app.py
if idade >= 18:
print("Maior de idade")
else:
print("Menor de idade")Ser menor de idade é um resultado possível, não uma falha da operação.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Decisão
Exceção pronta ou customizada?
app.py
raise ValueError("O valor deve ser positivo.")app.py
raise SaldoInsuficienteError(
"Não há saldo suficiente."
)Não é necessário criar uma classe para cada mensagem — criamos um novo tipo quando distinguir o problema ajuda o chamador a decidir. Ex.: saque negativo e falta de saldo são problemas diferentes.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Sintaxe
Criando uma exceção customizada
app.py
class SaldoInsuficienteError(Exception):
passclass cria um novo tipo;
SaldoInsuficienteError é o nome do novo tipo;
o sufixo Error segue a convenção das exceções do Python;
(Exception) indica herança do comportamento básico;
pass: não adicionamos atributos ou métodos agora.
Primeira aparição de herança da sequência — estudada formalmente na próxima aula.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Ponte para herança
A exceção específica também é uma Exception
app.py
erro = SaldoInsuficienteError(
"Saldo insuficiente."
)
print(isinstance(erro, SaldoInsuficienteError))
print(isinstance(erro, Exception))O primeiro resultado mostra o tipo específico; o segundo mostra que, por herança, o objeto também é uma Exception.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Exemplo
Validação no construtor
O construtor só cria a conta se o saldo inicial for válido.
conta.py
class ContaBancaria:
def __init__(self, titular, saldo=0):
if saldo < 0:
raise ValueError(
"O saldo inicial não pode ser negativo."
)
self.titular = titular
self.__saldo = saldo
@property
def saldo(self):
return self.__saldoPROGRAMAÇÃO ORIENTADA A OBJETOS
Exemplo
Regras do método sacar
conta.py
def sacar(self, valor):
if valor <= 0:
raise ValueError(
"O valor do saque deve ser positivo."
)
if valor > self.__saldo:
raise SaldoInsuficienteError(
"Saldo insuficiente para o saque."
)
self.__saldo -= valor
return self.__saldo1O valor precisa ser positivo, senão ocorre ValueError.
2A conta precisa ter saldo suficiente, senão ocorre SaldoInsuficienteError.
a subtração só acontece depois das duas verificações;
o método retorna o novo saldo.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Exemplo
Tratamentos diferentes para problemas diferentes
main.py
conta = ContaBancaria("Ana", 100)
try:
saldo_atual = conta.sacar(500)
print("Saldo atual:", saldo_atual)
except ValueError as erro:
print("Valor de saque inválido:", erro)
except SaldoInsuficienteError as erro:
print("Operação recusada:", erro)sacar(-20)tratado pelo bloco de ValueError
sacar(500)tratado pelo bloco de SaldoInsuficienteError
sacar(40)termina normalmente, imprime o novo saldo
PROGRAMAÇÃO ORIENTADA A OBJETOS
Prática integradora
Controle de estoque
Crie EstoqueInsuficienteError e a classe Produto
todo produto tem nome e quantidade em estoque; o estoque inicial não pode ser negativo;
a quantidade vendida deve ser maior que zero, senão lança ValueError;
uma venda maior que o estoque lança EstoqueInsuficienteError;
uma venda válida diminui o estoque e devolve a quantidade restante;
o código chamador trata os dois tipos de exceção separadamente.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Prática integradora
Casos de teste (estoque inicial = 5)
vender(2)venda concluída, estoque restante igual a 3
vender(0)tratamento de ValueError
vender(8)tratamento de EstoqueInsuficienteError
PROGRAMAÇÃO ORIENTADA A OBJETOS
Recapitulação
O que vimos hoje
raise lança uma exceção e interrompe o fluxo normal naquele ponto;
o programa procura um except compatível nas chamadas em execução;
return é conclusão normal; raise sinaliza que a operação não pôde ser concluída;
exceções prontas representam categorias gerais de problemas;
exceções customizadas identificam situações específicas do domínio;
uma exceção customizada funciona porque herda de Exception.
PROGRAMAÇÃO ORIENTADA A OBJETOS
Bilhete de saída
Respondam individualmente
1O que acontece com as linhas abaixo de um raise?
2Qual é a diferença entre return e raise?
3Quando uma exceção customizada pode ser útil?
4Por que é importante validar os dados antes de alterar os atributos do objeto?
5O que significa (Exception) na criação de uma exceção customizada?
PROGRAMAÇÃO ORIENTADA A OBJETOS
Próxima aula
Ponte para Herança
estoque.py
class EstoqueInsuficienteError(Exception):
passNa próxima aula, vamos estudar
o significado dos parênteses na declaração de uma classe;
o que uma classe pode receber de outra;
por que um objeto pertence ao tipo específico e ao geral;
como acrescentar ou modificar comportamentos herdados;
quando a herança representa bem uma relação entre classes.
PROGRAMAÇÃO ORIENTADA A OBJETOS


Próximo assunto: Herança
Dúvidas? Me chama!
vitor.silva@poa.ifrs.edu.br