Tratamento de exceções
Esta aula aborda o tratamento de exceções em Python, incluindo os blocos try/except/else/finally, os tipos de exceção, o uso de raise e boas práticas. O conteúdo é prático e progressivo, com exemplos de código e exercícios.
Em Python, exceções são eventos que ocorrem durante a execução de um programa e interrompem o fluxo normal do código. O tratamento de exceções permite que você lide com esses erros de forma controlada, evitando que o programa quebre inesperadamente. Nesta aula, vamos explorar os mecanismos que Python oferece para capturar, lançar e gerenciar exceções, além de boas práticas para escrever código robusto.
Dominar o tratamento de exceções é essencial para criar aplicações confiáveis e com boa experiência do usuário. Vamos começar com a estrutura fundamental: try/except.
try/except/else/finally
O bloco try é usado para envolver código que pode gerar uma exceção. Se uma exceção ocorrer, o bloco except correspondente é executado. Você pode especificar o tipo de exceção a ser capturada, ou usar um except genérico. O bloco else é executado se nenhuma exceção ocorrer no try, e o bloco finally é executado sempre, independentemente de exceções.
Exemplo básico:
try:
numero = int(input("Digite um número: "))
resultado = 10 / numero
except ValueError:
print("Erro: você não digitou um número válido.")
except ZeroDivisionError:
print("Erro: divisão por zero não é permitida.")
else:
print(f"Resultado: {resultado}")
finally:
print("Bloco finally sempre executado.")O else é útil para código que deve ser executado apenas se não houver exceções, e o finally é ideal para ações de limpeza, como fechar arquivos ou liberar recursos.
Tipos de exceção
Python possui diversas exceções embutidas, organizadas em hierarquia. A classe base é BaseException, da qual derivam Exception (para a maioria das exceções) e outras como SystemExit, KeyboardInterrupt. É importante capturar exceções específicas em vez de usar um except genérico, para evitar mascarar erros inesperados.
Principais exceções:
ValueError: quando uma função recebe um argumento com tipo correto mas valor inadequado.TypeError: quando uma operação recebe um tipo de dado incompatível.IndexError: ao acessar um índice de lista fora do intervalo.KeyError: ao acessar uma chave de dicionário inexistente.FileNotFoundError: ao tentar abrir um arquivo que não existe.
Exemplo:
try:
lista = [1, 2, 3]
print(lista[5])
except IndexError:
print("Índice fora do intervalo.")Você também pode capturar múltiplas exceções em um único except usando tuplas:
try:
# código que pode gerar ValueError ou TypeError
except (ValueError, TypeError) as e:
print(f"Erro: {e}")raise
A instrução raise permite lançar exceções intencionalmente. Você pode usar exceções embutidas ou criar suas próprias exceções personalizadas (herdando de Exception). Isso é útil para sinalizar condições excepcionais em seu código.
Exemplo:
def dividir(a, b):
if b == 0:
raise ValueError("Divisor não pode ser zero.")
return a / b
try:
resultado = dividir(10, 0)
except ValueError as e:
print(e)Para criar uma exceção personalizada:
class SaldoInsuficienteError(Exception):
pass
def sacar(saldo, valor):
if valor > saldo:
raise SaldoInsuficienteError("Saldo insuficiente para saque.")
return saldo - valorBoas práticas
Ao tratar exceções, siga estas recomendações:
- Seja específico: capture exceções específicas em vez de genéricas (
except Exception). Eviteexcept:sem tipo, pois captura atéKeyboardInterrupt. - Não silencie exceções: evite except vazios ou que apenas passam; pelo menos registre o erro.
- Use finally para limpeza: feche arquivos, conexões de rede, etc., no finally.
- Evite usar exceções para controle de fluxo: exceções são para situações excepcionais, não para lógica normal.
- Documente as exceções: indique em docstrings quais exceções sua função pode lançar.
Exemplo de boa prática:
try:
with open("arquivo.txt", "r") as f:
conteudo = f.read()
except FileNotFoundError:
print("Arquivo não encontrado.")
except PermissionError:
print("Sem permissão para ler o arquivo.")
except Exception as e:
print(f"Erro inesperado: {e}")
raise # relança a exceção para depuraçãoReferências
- Python Tutorial: Errors and Exceptions
- Python Built-in Exceptions
- The try statement (Python Reference)
- Real Python: Python Exceptions
- Python Glossary: raise
Exercícios
Crie uma função que receba dois números e retorne a divisão do primeiro pelo segundo. Trate exceções para divisão por zero e para entradas não numéricas.
✓ Resposta:def divisao_segura(a, b): try: resultado = a / b except ZeroDivisionError: return "Erro: divisão por zero." except TypeError: return "Erro: entradas devem ser números." else: return resultado print(divisao_segura(10, 2)) # 5.0 print(divisao_segura(10, 0)) # Erro: divisão por zero. print(divisao_segura(10, "a")) # Erro: entradas devem ser números.Escreva um programa que peça ao usuário um número inteiro e exiba seu inverso (1/n). Capture exceções para entrada inválida e divisão por zero.
✓ Resposta:try: n = int(input("Digite um número inteiro: ")) inverso = 1 / n except ValueError: print("Erro: você não digitou um número inteiro.") except ZeroDivisionError: print("Erro: não é possível calcular inverso de zero.") else: print(f"O inverso é {inverso}") finally: print("Fim do programa.")Crie uma exceção personalizada chamada
IdadeInvalidaError. Escreva uma função que receba uma idade e lance essa exceção se a idade for menor que 0 ou maior que 150. Trate a exceção adequadamente.✓ Resposta:class IdadeInvalidaError(Exception): pass def validar_idade(idade): if idade < 0 or idade > 150: raise IdadeInvalidaError(f"Idade {idade} inválida. Deve estar entre 0 e 150.") return idade try: idade = int(input("Digite sua idade: ")) validar_idade(idade) print(f"Idade {idade} válida.") except ValueError: print("Erro: entrada não é um número.") except IdadeInvalidaError as e: print(e)Escreva um bloco try/except/finally que tente abrir um arquivo chamado "dados.txt" para leitura. Se o arquivo não existir, capture FileNotFoundError e crie o arquivo vazio. Em finally, feche o arquivo (use with para simplificar).
✓ Resposta:try: with open("dados.txt", "r") as arquivo: conteudo = arquivo.read() print("Arquivo lido com sucesso.") except FileNotFoundError: print("Arquivo não encontrado. Criando arquivo vazio.") with open("dados.txt", "w") as arquivo: pass finally: print("Operação concluída.")Implemente uma calculadora simples que pede dois números e uma operação (+, -, *, /). Use exceções para tratar entradas inválidas e divisão por zero. Inclua um bloco else para exibir o resultado e finally para agradecer.
✓ Resposta:def calculadora(): try: a = float(input("Digite o primeiro número: ")) b = float(input("Digite o segundo número: ")) op = input("Digite a operação (+, -, *, /): ") if op == "+": resultado = a + b elif op == "-": resultado = a - b elif op == "*": resultado = a * b elif op == "/": resultado = a / b else: print("Operação inválida.") return except ValueError: print("Erro: entradas devem ser números.") except ZeroDivisionError: print("Erro: divisão por zero.") else: print(f"Resultado: {resultado}") finally: print("Obrigado por usar a calculadora!") calculadora()