O Python é fácil de escrever, mas um tratamento de erros descuidado pode transformar uma aplicação funcional em uma que falha silenciosamente em produção. Sem stack trace, sem alerta — apenas uma funcionalidade que parou de funcionar há três dias e ninguém percebeu.
Este artigo cobre 7 padrões de tratamento de erros que você realmente usará no trabalho. Todo snippet roda em Python 3.6+ puro, sem dependências.
Uma coisa a ter em mente antes de começar: tratamento de exceções não é algo que você adiciona no final. É parte do design. O melhor código não previne erros de acontecer — garante que os erros não derrubem o sistema.
1. try / except básico — Comece aqui
A base de todo tratamento de erros em Python. Capture tipos específicos de exceção e responda a cada um de forma diferente.
def divide(a, b):
try:
return a / b
except ZeroDivisionError:
return "Cannot divide by zero"
except TypeError:
return "Please provide numbers"
print(divide(10, 2)) # 5.0
print(divide(10, 0)) # Cannot divide by zero
print(divide(10, "a")) # Please provide numbers
A regra de ouro: nunca escreva um except: vazio. Sempre nomeie o tipo de exceção. Um except vazio captura tudo — incluindo KeyboardInterrupt e SystemExit — e torna o debug praticamente impossível.
O erro clássico de iniciante:
# NÃO faça isso
except Exception:
pass
Isso engole todo erro silenciosamente. Quando algo quebrar três semanas depois, você terá zero pistas do que deu errado. No mínimo, registre a exceção:
except ZeroDivisionError as e:
logging.error("Division failed: %s", e)
Conclusão: Capture exceções por tipo. Trate except: pass como uma bomba-relógio.
2. finally — Limpeza Garantida
Quando você abre um arquivo, uma conexão de banco de dados ou um socket de rede, precisa fechá-lo — quer a operação tenha sucesso ou não. É para isso que serve o finally.
f = None
try:
f = open("data.txt", "w")
f.write("hello")
except IOError as e:
print("Write failed:", e)
finally:
if f:
f.close()
print("Cleanup done")
O bloco finally roda não importa o que aconteça — mesmo se uma exceção for lançada, mesmo se você fizer return de dentro do bloco try.
3. A Instrução with — Como os Profissionais Fazem
Na prática, você raramente escreverá finally: f.close() à mão. A instrução with cuida disso automaticamente — e de forma mais limpa.
try:
with open("data.txt", "w") as f:
f.write("hello")
except IOError as e:
print("Write failed:", e)
A instrução with garante que o arquivo seja fechado quando o bloco termina, mesmo se ocorrer uma exceção. Funciona com qualquer objeto que implemente o protocolo de gerenciador de contexto.
Você pode abrir múltiplos arquivos em uma instrução:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
4. Re-lançando Exceções com raise
Às vezes você precisa registrar um erro e deixá-lo propagar. Um raise simples dentro de um bloco except re-lança a exceção original com seu traceback completo intacto.
import logging
def process(data):
try:
return transform(data)
except Exception as e:
logging.error("Processing failed: %s", e)
raise
Sem o raise, a função retorna None silenciosamente, e o chamador assume que tudo funcionou. Se quiser envolver o erro original com contexto adicional, use encadeamento de exceções:
class ProcessingError(Exception):
pass
try:
result = transform(data)
except ValueError as e:
raise ProcessingError("Bad input data") from e
5. Exceções Personalizadas — Erros que Significam Algo
Exceções embutidas são genéricas. Em uma aplicação real, ValueError poderia significar cem coisas diferentes. Exceções personalizadas tornam seu código auto-documentado.
class ValidationError(Exception):
"""Lançada quando dados de entrada falham na validação."""
pass
class APIError(Exception):
"""Lançada quando uma chamada a API externa falha."""
def __init__(self, status_code, message):
self.status_code = status_code
super().__init__(f"{status_code}: {message}")
def validate_age(age):
if age < 0:
raise ValidationError("A idade não pode ser negativa")
return age
try:
validate_age(-5)
except ValidationError as e:
print(e) # A idade não pode ser negativa
6. assert — Verificações Apenas para Desenvolvimento
assert é uma forma rápida de verificar suposições durante o desenvolvimento. Se a condição for falsa, lança AssertionError.
def withdraw(balance, amount):
assert amount > 0, "Amount must be positive"
assert balance >= amount, "Insufficient funds"
return balance - amount
print(withdraw(100, 50)) # 50
print(withdraw(100, 200)) # AssertionError
O crítico sobre assert: ele pode ser desabilitado. Executar python -O (modo otimizado) remove todas as instruções assert. Para validação em produção, use verificações explícitas:
def withdraw(balance, amount):
if amount <= 0:
raise ValueError("Valor deve ser positivo")
if balance < amount:
raise ValueError("Saldo insuficiente")
return balance - amount
7. Lógica de Retry — Porque Redes Falham
Chamadas de API expiram. Conexões de banco caem. Lookups de DNS falham. Em qualquer sistema que fale com serviços externos, retry não é opcional.
import time
import random
def call_api():
if random.random() < 0.7:
raise ConnectionError("Servidor indisponível")
return {"status": "ok"}
max_retries = 5
for attempt in range(max_retries):
try:
result = call_api()
print("Sucesso:", result)
break
except ConnectionError as e:
wait = 2 ** attempt # backoff exponencial
print(f"Tentativa {attempt + 1} falhou, retentando em {wait}s...")
time.sleep(wait)
else:
print("Todas as tentativas esgotadas")
Pontos-chave para lógica de retry em produção: sempre defina um número máximo de retries; use backoff exponencial; só retente em erros transitórios.
Resumo: Tratamento de Erros é Design
1. try/except — Capture exceções específicas, nunca except vazio.
2. finally — Limpeza garantida de recursos.
3. with — A forma pythônica de gerenciar recursos.
4. raise — Registre e re-lance, não engula erros.
5. Exceções personalizadas — Tipos de erro auto-documentados.
6. assert — Apenas verificações em desenvolvimento.
7. Retry — Obrigatório para qualquer coisa envolvendo rede.
Os desenvolvedores acordados às 3h da manhã não são os que escrevem código esperto. São os que esqueceram de tratar o caso de erro. Tratamento de exceções não é sobre prevenir erros — é sobre garantir que os erros não derrubem o sistema.

Leave a Reply