Guia de estudo

22/05/2026 · Aula 12

Tratamento de Exceções

Programas que não morrem no primeiro tropeço.

Programação Orientada a Objetos com Python
Tecnologia em Análise e Desenvolvimento de Sistemas

try / except / else / finally raise Exceções customizadas Hierarquia de erros

plano de voo

O que vamos aprender hoje

01

O Buraco

Por que devolver None ou imprimir um aviso é uma forma frágil de tratar erro.

02

A Captura

Como try/except separa o que detecta o erro do que o trata.

03

Erros Próprios

Como criar suas próprias exceções para falar a língua do seu sistema.

04

Na Prática

Sistema bancário com SaldoInsuficienteError e validação de operações.

de onde paramos · 2 dias atrás

Sobrecarga — o que vimos na aula 11

  • 🎚️ Simular sobrecarga de método: uma versão flexível com default, *args e **kwargs no lugar de várias versões fixas.
  • Sobrecarga de operador: dunder methods (__add__, __eq__, __str__) ensinam seus objetos a responder a +, == e print.
  • 🌉 A pendência: a classe Dinheiro devolvia None quando as moedas eram diferentes. Funcionou — mas a gente prometeu voltar nisso hoje.

memória muscular

O Dinheiro da aula 11 — e o seu defeito

Quando as moedas batiam, somava. Quando não batiam, imprimia um aviso e devolvia None. Parecia razoável. Não era.

🤫
O print avisa, mas quem chamou a soma não é obrigado a ler. O programa continua rodando com um None na mão.
🚩
O return None é um valor mágico: quem recebe precisa lembrar de checar se veio None. Esquecer é fácil.
dinheiro_aula_11.py
class Dinheiro:
    def __init__(self, valor, moeda):
        self.valor = valor
        self.moeda = moeda

    def __add__(self, outro):
        if self.moeda != outro.moeda:
            print(f"⚠️  Não dá pra somar {self.moeda} com {outro.moeda}")
            return None          # ← o defeito mora aqui
        return Dinheiro(self.valor + outro.valor, self.moeda)

carteira = Dinheiro(10, "BRL")
total = carteira + Dinheiro(5, "USD")   # imprime o aviso...
print(total)                            # None  ← e segue como se nada fosse

pergunta pra turma · 2 minutos

Pra esquentar a cabeça

  • Aquele total que virou None não fica parado — ele é usado mais pra frente no programa. O que acontece quando alguém escreve print(total.valor) três telas depois, achando que total é um Dinheiro de verdade?

a resposta · e por que ela importa

O erro estoura longe de onde nasceu

O None viaja silencioso pelo programa até alguém tentar usá-lo como se fosse um objeto. Aí, sim, trava — mas numa linha que não tem nada a ver com a soma.

🧭
O AttributeError aponta pra linha do total.valor — não pra soma das moedas, que foi o verdadeiro problema. Debugar isso é caçar fantasma.
💣
Lição: erro mascarado não some — só explode mais tarde, mais longe e mais difícil de rastrear.
erro_distante.py
carteira = Dinheiro(10, "BRL")
total = carteira + Dinheiro(5, "USD")   # aqui imprimiu o aviso e devolveu None

# ... 50 linhas depois, em outra função, outro arquivo ...
print(total.valor)
# AttributeError: 'NoneType' object has no attribute 'valor'

começando pelo problema

Duas reações ruins a um erro

  • 🎭 Devolver um valor mágico (None, -1, False, ""): quem chama precisa adivinhar que aquele valor significa "deu errado" — e lembrar de checar toda vez.
  • 🖨️ Imprimir e seguir em frente (print("erro!")): o aviso some no meio de mil outras linhas do terminal, e o programa continua como se estivesse tudo bem.

É exatamente o problema de hoje

Como uma função pode parar tudo e gritar "deu errado!" de um jeito que quem chamou seja obrigado a lidar — ou o programa para na hora, no lugar certo?

o problema em código

O Python já faz isso o tempo todo

Você já viu erros que param o programa na hora. Eles têm nome e sobrenome — e param exatamente na linha que causou o problema.

🛑
Cada erro para o programa imediatamente, na linha exata, com um nome que diz o que houve. Isso é o oposto do None silencioso.
💡
A novidade de hoje: você pode provocar esses erros de propósito (raise) e também capturá-los pra não deixar o programa morrer (try/except).
erros_nativos.py
print(10 / 0)
# ZeroDivisionError: division by zero

idade = int("abc")
# ValueError: invalid literal for int() with base 10: 'abc'

lista = [1, 2, 3]
print(lista[10])
# IndexError: list index out of range

pessoa = {"nome": "Ana"}
print(pessoa["idade"])
# KeyError: 'idade'

a ideia da solução

Separe quem detecta de quem trata

  • 🚨 Quem detecta (raise): a função que percebe o problema só dispara o alarme — "saldo insuficiente!" — e para ali mesmo. Não precisa saber o que fazer depois.
  • 🧰 Quem trata (try/except): quem chamou a função decide a reação — mostrar mensagem pro usuário, tentar de novo, registrar num log. Cada contexto reage do seu jeito.

Mudança de mentalidade

Saímos de "a função tenta resolver tudo sozinha" para "a função avisa, quem chamou decide".

as peças que você vai encontrar

Antes do código, conhece quem entra em cena

  • 🚨 raise: dispara uma exceção de propósito. raise ValueError("mensagem") para o programa ali e sobe o erro pra quem chamou.
  • 🛡️ try: marca um bloco "arriscado" — código que pode dar erro. Você diz ao Python "tenta isso aqui, e fica de olho".
  • 🪤 except: a rede de segurança. Se o bloco try levantar uma exceção, o except captura e roda um plano B em vez de deixar o programa morrer.

Mais duas, pra depois

Existem ainda else (roda se não deu erro) e finally (roda sempre). Vamos chegar nelas — comece pelo trio acima.

ferramenta 1 · capturar

try / except — a rede de segurança

Envolva o código arriscado num try. Se ele estourar, o except entra em ação — e o programa não morre.

🛡️
Se o usuário digitar 42, o try roda inteiro e o except é ignorado.
🪤
Se digitar "abc", o int() levanta ValueError, o try é interrompido na hora e o except assume — sem travar o programa.
try_except.py
try:
    idade = int(input("Digite sua idade: "))
    print(f"Ano que vem você faz {idade + 1}")
except ValueError:
    print("Isso não é um número válido!")

print("O programa continua rodando.")   # roda mesmo se deu erro

ferramenta 2 · disparar

raise — o alarme que você aciona

Quando sua função percebe uma situação inválida, ela mesma levanta a exceção. Não devolve None — dispara o alarme.

🚨
raise interrompe a função na hora — as linhas depois dele não rodam. O erro sobe pra quem chamou sacar.
🆚
Compare com a aula 11: em vez de return None e um print, agora a função se recusa a devolver um valor errado.
raise.py
def sacar(saldo, valor):
    if valor > saldo:
        raise ValueError("Saldo insuficiente para o saque")
    return saldo - valor

print(sacar(100, 30))    # 70  ← deu certo
print(sacar(100, 150))   # para aqui:
# ValueError: Saldo insuficiente para o saque

capturar com pontaria

Um except para cada tipo de erro

Você pode ter vários except no mesmo try — cada um trata um tipo específico de exceção. O Python escolhe o que combina.

🎯
Cada except mira um tipo. Capturar específico deixa claro qual problema você esperava e como reagir a cada um.
⚠️
Existe o except Exception: que captura quase tudo — mas use com parcimônia. Capturar específico é quase sempre melhor (mais sobre isso no fim da aula).
except_especifico.py
def dividir(a, b):
    return int(a) / int(b)

try:
    resultado = dividir("10", "0")
except ValueError:
    print("Digite apenas números!")
except ZeroDivisionError:
    print("Não dá pra dividir por zero!")
# saída: Não dá pra dividir por zero!

lendo o erro capturado

as erro — pegue a exceção pela mão

Com except ... as erro, você guarda a exceção numa variável e pode ler a mensagem que veio dentro dela.

🤝
erro é o objeto da exceção. Imprimi-lo mostra a mensagem que quem deu raise escreveu lá atrás.
🔎
Guardar a exceção permite registrar em log, mostrar detalhe pro usuário, ou — como veremos — ler dados extras que você mesmo colocou nela.
as_erro.py
try:
    numero = int("abc")
except ValueError as erro:
    print(f"Deu ruim: {erro}")
    # Deu ruim: invalid literal for int() with base 10: 'abc'

as duas peças que faltavam

else e finally — completando o quarteto

else roda só quando o try deu certo. finally roda sempre — deu certo ou não. Ideal pra limpeza (fechar arquivo, conexão).

else separa o "código que só faz sentido se deu certo" do bloco arriscado — deixa o try enxuto, só com a parte que pode falhar.
🧹
finally é a faxina garantida: roda mesmo se um raise escapar. Perfeito pra liberar recursos (assunto que volta na aula 13, com arquivos).
else_finally.py
try:
    numero = int("42")
except ValueError:
    print("Não era número")
else:
    print(f"Converteu certo: {numero}")   # roda só se NÃO deu erro
finally:
    print("Fim da tentativa")              # roda SEMPRE

# saída:
# Converteu certo: 42
# Fim da tentativa

agora podemos dar o nome

Isso se chama Exceção

  • 📦 Exceção é um objeto — instância de uma classe como ValueError ou ZeroDivisionError. Carrega uma mensagem e pode carregar dados.
  • 🆚 Erro vs. exceção: no dia a dia usamos como sinônimos. Tecnicamente, a exceção é o objeto; levantar/tratar é o que você faz com ele.

Regra de ouro

Não use exceção pra controlar fluxo normal (um if resolve). Use pra sinalizar o que é excepcional — o que foge do esperado.

antes e depois · lado a lado

A diferença que as exceções fazem

❌ Retorno frágil (None / aviso)

  • Quem chama precisa lembrar de checar o retorno
  • Erro mascarado explode longe da causa
  • print some no meio do terminal
  • O programa segue com dado inválido

✅ Exceção (raise / except)

  • O erro para na linha exata que o causou
  • Quem chama é obrigado a tratar (ou o programa para)
  • A mensagem diz o tipo e o motivo
  • Dado inválido nunca segue adiante

analogia do cotidiano

O disjuntor da casa

  • O raise é o disjuntor desarmando: na primeira sobrecarga, corta tudo. Melhor parar agora do que deixar a fiação esquentar em silêncio.
  • 🔧 O try/except é você no quadro de luz: percebe que desarmou, entende qual circuito foi e decide o que fazer — religar, chamar o eletricista, isolar o problema.

Outra forma de pensar

Engolir o erro (except: pass) é colar fita isolante no disjuntor pra ele parar de desarmar. O problema não sumiu — você só desligou o aviso.

toda exceção tem família

A hierarquia de exceções do Python

Exceções são classes — e classes têm herança (aulas 07-10). Toda exceção desce de Exception. Isso significa que capturar uma classe-mãe captura também as filhas.

🌳
Capturar ArithmeticError pega ZeroDivisionError também — porque é uma filha. Herança da aula 07, agora aplicada a erros.
🎚️
Quanto mais alto na árvore você captura, mais erros pega. except Exception pega quase tudo — poderoso e perigoso ao mesmo tempo.
hierarquia.py
# BaseException
#  └── Exception              ← capture a partir daqui
#       ├── ArithmeticError
#       │    └── ZeroDivisionError
#       ├── LookupError
#       │    ├── IndexError
#       │    └── KeyError
#       ├── ValueError
#       └── TypeError

try:
    resultado = 10 / 0
except ArithmeticError:        # pai de ZeroDivisionError
    print("Capturado pela classe-mãe!")
# saída: Capturado pela classe-mãe!

panorama · as exceções nativas mais comuns

Os erros que você mais vai encontrar

item detalhe
ValueError Tipo certo, valor errado. int("abc") — é string, mas não dá pra virar número.
TypeError Tipo errado pra operação. "texto" + 5 — não dá pra somar texto com número.
ZeroDivisionError Divisão (ou módulo) por zero. 10 / 0.
IndexError Índice fora do tamanho da lista. [1, 2, 3][10].
KeyError Chave que não existe no dicionário. {"a": 1}["b"].
FileNotFoundError Arquivo que não existe ao tentar abrir. Volta forte na aula 13.
AttributeError Atributo/método que não existe no objeto. None.valor — foi o erro do nosso Dinheiro.
Exception A classe-mãe de quase todas. É dela que herdam as suas exceções customizadas.

parte 2 · seus próprios erros

E quando o erro é do seu domínio?

  • 🏷️ A ideia: uma exceção com nome próprio (SaldoInsuficienteError) conta a história sem precisar ler a mensagem. O tipo do erro já é a documentação.
  • 🧬 Como se faz: é só uma classe que herda de Exception. Toda a maquinaria de raise e except já funciona de graça — herança da aula 07.

A pergunta de hoje (parte 2)

Como capturar exatamente o erro do meu sistema, sem confundir com um ValueError qualquer que veio de outro lugar?

a solução em código

Criar uma exceção é criar uma classe

Uma linha. Herda de Exception, ganha um nome que fala a língua do seu sistema, e já pode ser levantada e capturada.

🏷️
O nome é a documentação: except SaldoInsuficienteError diz exatamente o que está sendo tratado. Nenhum comentário necessário.
🎯
Captura sem ambiguidade: esse except só pega saldo insuficiente — um ValueError vindo de outro ponto passa direto, como deveria.
excecao_customizada.py
class SaldoInsuficienteError(Exception):
    pass

def sacar(saldo, valor):
    if valor > saldo:
        raise SaldoInsuficienteError("Você não tem saldo suficiente")
    return saldo - valor

try:
    sacar(100, 150)
except SaldoInsuficienteError as erro:
    print(f"Operação negada: {erro}")
# saída: Operação negada: Você não tem saldo suficiente

exceção que carrega dados

Sua exceção pode levar informação junto

Defina um __init__ (aula 02!) e a exceção carrega os dados do problema. Quem captura lê esses dados pra reagir com precisão.

📦
A exceção vira um pacote: além da mensagem, carrega saldo, valor e falta. Quem captura usa esses dados pra decidir o que mostrar.
🔗
super().__init__(...) é o mesmo super() da aula 07 — aqui ele entrega a mensagem pra classe-mãe Exception guardar.
excecao_com_dados.py
class SaldoInsuficienteError(Exception):
    def __init__(self, saldo, valor):
        self.saldo = saldo
        self.valor = valor
        self.falta = valor - saldo
        # super() monta a mensagem que aparece no print do erro
        super().__init__(f"Faltam R$ {self.falta:.2f} para sacar R$ {valor:.2f}")

try:
    raise SaldoInsuficienteError(saldo=100, valor=150)
except SaldoInsuficienteError as erro:
    print(erro)            # Faltam R$ 50.00 para sacar R$ 150.00
    print(erro.falta)      # 50  ← dá pra ler os dados do erro

anatomia

O bloco completo, parte por parte

try, except, else e finally têm uma ordem fixa e um papel cada. Decora essa sequência.

1

try — o código arriscado

Aqui vai só o que pode falhar. Quanto menor o bloco, mais fácil saber o que deu errado.

2

except — o plano B

Um ou vários, cada um pra um tipo de exceção. Roda só se o try levantar aquele erro.

3

else — deu tudo certo

Opcional. Roda apenas quando o try terminou sem nenhuma exceção. Bom pra separar o "caminho feliz".

4

finally — aconteça o que acontecer

Opcional. Roda sempre, no fim de tudo. É onde você libera recursos (fechar arquivo, conexão, etc.).

uso com critério

A regra de ouro: não engula erros

  • 🙈 Engolir o erro (except: pass) é desligar o alarme de incêndio porque o barulho incomoda. O fogo continua — você só parou de ser avisado.
  • 🎯 Capture específico: except ValueError em vez de except Exception. Capturar largo demais esconde até erros de digitação (um NameError que deveria estourar).

Princípio prático

Se você captura um erro, faça algo útil: trate, registre em log, ou levante de novo (raise). Capturar pra ignorar é pior que não capturar.

armadilha · não faça isso

O except que esconde tudo

Os dois blocos abaixo "funcionam" — nenhum trava o programa. Mas ambos transformam um erro real num mistério insolúvel.

🙈
O except: pass é o pior dos mundos: o erro acontece, é capturado e jogado fora. Zero pistas pra quem for debugar.
🐛
O except Exception largo engole o NameError do nome escrito errado — um bug que o Python queria ter te mostrado.
anti_padrao.py
# ❌ Engolir: o erro some, mas o problema continua
try:
    numero = int("abc")
except:
    pass            # ninguém nunca vai saber o que deu errado

# ❌ Genérico demais: mascara até bug de digitação
try:
    total = calcualr_preco(100)   # 'calcualr' está escrito errado
except Exception:
    total = 0                     # esconde o NameError de propósito

# ✅ Específico e honesto
try:
    numero = int("abc")
except ValueError as erro:
    print(f"Entrada inválida: {erro}")

por que isso importa

O que o tratamento de exceções entrega

🛡️

Robustez

O programa sobrevive a entradas ruins e falhas pontuais sem morrer no primeiro tropeço.

🧭

Erro na origem

A falha para na linha que a causou — não 50 linhas depois, disfarçada.

🗣️

Mensagens claras

O usuário vê "saldo insuficiente", não um traceback assustador.

🏷️

Domínio no código

Exceções customizadas dão nome aos erros do seu sistema — viram documentação viva.

🧹

Limpeza garantida

finally libera recursos mesmo quando algo dá errado no meio.

🤝

Contrato claro

Quem usa sua função sabe quais erros ela pode levantar — e como tratá-los.

glossário rápido

Os termos de hoje, em uma frase cada

item detalhe
Exceção Objeto que representa um erro. Instância de uma classe como ValueError ou da sua própria.
raise Levanta (dispara) uma exceção de propósito. Interrompe a função e sobe o erro pra quem chamou.
try Marca o bloco de código arriscado que pode levantar uma exceção.
except Captura uma exceção levantada no try e executa o plano B. Pode mirar um tipo específico.
else Roda apenas se o try terminou sem nenhuma exceção. É o caminho feliz.
finally Roda sempre, com erro ou sem erro. Usado pra liberar recursos (limpeza).
Hierarquia de exceções Exceções são classes com herança. Capturar a classe-mãe captura também as filhas.
Exceção customizada Classe que herda de Exception pra representar um erro específico do seu domínio.
Engolir erro Anti-padrão: capturar uma exceção e não fazer nada útil (except: pass).

laboratório em sala · duplas

Exercício ao Vivo: Conta Bancária

Em duplas. 30 minutos. Objetivo: uma ContaBancaria que se recusa a fazer operações inválidas — levantando exceções em vez de devolver valores mágicos.

1

Crie a exceção customizada

SaldoInsuficienteError(Exception) com um __init__ que guarda saldo, valor e calcula quanto falta.

2

Monte a ContaBancaria

Com titular e saldo. O método depositar(valor) levanta ValueError se o valor não for positivo.

3

Saque que se defende

sacar(valor) levanta ValueError se o valor for inválido e SaldoInsuficienteError se faltar saldo.

4

Use com try/except

Faça um saque válido e um inválido dentro de um try, com um except pra cada tipo de erro e um finally mostrando o saldo final.

resolução · passo 1

Começamos pela exceção

  • 🏷️ Herdamos de Exception e damos o nome do domínio: SaldoInsuficienteError. Esse nome vai aparecer no except e contar a história sozinho.
  • 📦 O __init__ guarda saldo e valor, calcula falta e monta a mensagem via super().__init__.

Detalhe importante

A exceção é só uma classe comum — tudo o que você aprendeu sobre __init__ e super() (aulas 02 e 07) vale aqui.

resolução · passo 1

A exceção SaldoInsuficienteError

Ela guarda o contexto do erro: quanto tinha, quanto se tentou sacar e quanto faltou.

📦
Três atributos (saldo, valor_saque, falta) ficam disponíveis pra quem capturar o erro.
📝
A mensagem completa vai pro super().__init__ — é o que aparece quando você dá print(erro).
banco.py
class SaldoInsuficienteError(Exception):
    def __init__(self, saldo, valor_saque):
        self.saldo = saldo
        self.valor_saque = valor_saque
        self.falta = valor_saque - saldo
        super().__init__(
            f"Saldo de R$ {saldo:.2f} insuficiente para sacar "
            f"R$ {valor_saque:.2f} (faltam R$ {self.falta:.2f})"
        )

resolução · passos 2 e 3

A ContaBancaria que se defende

Cada método valida antes de agir. Valor inválido? ValueError. Saldo curto? SaldoInsuficienteError. Nenhuma operação errada passa.

🛡️
Validar primeiro, agir depois. Se algo está errado, a função levanta o erro e nem chega a mexer no saldo.
🎯
Dois tipos de erro, dois raise: genérico (ValueError) pro valor inválido, específico (SaldoInsuficienteError) pro problema do domínio.
banco.py (continuação)
class ContaBancaria:
    def __init__(self, titular, saldo=0):
        self.titular = titular
        self.saldo = saldo

    def depositar(self, valor):
        if valor <= 0:
            raise ValueError("O valor do depósito deve ser positivo")
        self.saldo += valor
        return self.saldo

    def sacar(self, valor):
        if valor <= 0:
            raise ValueError("O valor do saque deve ser positivo")
        if valor > self.saldo:
            raise SaldoInsuficienteError(self.saldo, valor)
        self.saldo -= valor
        return self.saldo

resolução · passo 4

Usando a conta com try/except/finally

Um saque válido, um que estoura. Cada erro tem seu except, e o finally mostra o saldo aconteça o que acontecer.

🪤
O segundo sacar levanta a exceção; a linha seguinte é pulada e o except certo assume.
🔎
erro.falta lê o dado que guardamos na exceção — a mensagem pro usuário fica precisa, não genérica.
main.py
from banco import ContaBancaria, SaldoInsuficienteError

conta = ContaBancaria("Ana", saldo=100)

try:
    conta.sacar(30)
    print(f"Saque OK. Saldo: R$ {conta.saldo:.2f}")
    conta.sacar(500)   # 💥 estoura aqui
    print("Esta linha nunca roda")
except SaldoInsuficienteError as erro:
    print(f"❌ {erro}")
    print(f"   Deposite mais R$ {erro.falta:.2f} para conseguir sacar.")
except ValueError as erro:
    print(f"❌ Valor inválido: {erro}")
finally:
    print(f"Saldo final: R$ {conta.saldo:.2f}")

resolução · saída

Saída esperada no terminal

O saque válido passa, o inválido é barrado com mensagem clara, e o saldo final aparece intacto — o saque que falhou não tirou nada.

O saque inválido não alterou o saldo: a validação barrou antes de mexer no dinheiro. Saldo continua R$ 70,00.
🧹
O finally rodou mesmo com a exceção no meio — por isso o saldo final aparece sempre.
terminal
$ python main.py
Saque OK. Saldo: R$ 70.00
❌ Saldo de R$ 70.00 insuficiente para sacar R$ 500.00 (faltam R$ 430.00)
   Deposite mais R$ 430.00 para conseguir sacar.
Saldo final: R$ 70.00

encerramento

O que dominamos hoje

  • O problema: devolver None ou imprimir aviso deixa o erro escapar e explodir longe da causa.
  • A solução: raise dispara o erro na origem; try/except captura e trata onde faz sentido.
  • O quarteto: try (arriscado), except (plano B), else (deu certo), finally (sempre).
  • A família: exceções são classes com herança — capturar a mãe pega as filhas.
  • Erros próprios: herde de Exception pra criar exceções com nome e dados do seu domínio.
  • Na prática: conta bancária que se recusa a fazer operação inválida — e diz exatamente o que faltou.

exercícios · visão geral

Para praticar em casa

Sete exercícios em quatro níveis. Faça pelo menos um de cada nível antes da próxima aula.

01

Fáceis

1 exercício — Conversor seguro. Foco: try/except com erros nativos.

02

Médios

2 exercícios — Validador de idade e Estoque. Foco: raise e primeira exceção customizada.

03

Difíceis

2 exercícios — Dinheiro 2.0 e Validador de cadastro. Foco: refatorar com exceções e carregar dados no erro.

04

Avançado

1 exercício — Hierarquia de erros bancários. Foco: criar uma família de exceções customizadas.

exercícios · nível fácil

Para fixar try/except

01

Conversor seguro

Função ler_inteiro(texto) que pede um número ao usuário e usa try/except ValueError pra repetir o pedido até receber um número válido. Foco: capturar ValueError de int() num laço.

exercícios · nível médio

Levantar e criar erros

03

Validador de idade

Função validar_idade(idade) que levanta ValueError com mensagem clara se a idade for negativa ou maior que 150. Teste chamando dentro de um try/except. Foco: usar raise pra barrar entrada inválida.

04

Estoque vazio

Classe Estoque com uma lista de itens e o método remover(). Crie a exceção EstoqueVazioError e levante-a quando tentarem remover de um estoque vazio. Foco: primeira exceção customizada.

exercícios · nível difícil

Para ir além

05

Dinheiro 2.0

Refatore a classe Dinheiro da aula 11: em vez de imprimir aviso e devolver None quando as moedas diferem, crie MoedaIncompativelError e levante-a em __add__ e __sub__. Foco: trocar valor mágico por exceção — a promessa da aula 11.

06

Validador de cadastro

Crie CadastroInvalidoError que carrega o campo com problema. A função validar_cadastro(nome, email, idade) levanta a exceção indicando qual campo falhou (nome vazio, e-mail sem @, idade fora da faixa). Foco: exceção que carrega dados do erro.

exercícios · nível avançado

O desafio que junta tudo

Um exercício só, que usa hierarquia de exceções e captura por classe-mãe.

07

Hierarquia de erros bancários

Crie ContaError(Exception) como base, e duas filhas: SaldoInsuficienteError e ValorInvalidoError. Refatore a ContaBancaria do laboratório pra levantar as filhas. No main, mostre que um único except ContaError captura as duas — porque ambas herdam da base. Foco: herança aplicada a exceções (a hierarquia da aula).

próxima aula

Aula 13 · 27/05

Manipulação de Arquivos

Hoje garantimos que o programa não morre no primeiro tropeço. Na próxima aula, aprendemos a fazer ele lembrar das coisas: ler e escrever arquivos, salvar objetos em JSON — e o finally de hoje vira o with que fecha tudo sozinho.

open() e with Arquivos .txt e .csv Módulo json Persistência de dados