Depuração, Logs, Erros e Diagnóstico
Lição 10 de 15 · Conteúdo aberto
Depuração, Logs, Erros e Diagnóstico
Proficiência em Python não é apenas escrever código que funciona quando tudo está correto. É saber investigar falhas, ler mensagens de erro, reproduzir problemas e registrar informações úteis para manutenção.
Objetivo
Ao final, você deve saber:
- ler traceback;
- reproduzir erros;
- usar
printde forma temporária; - usar
breakpoint; - registrar logs com
logging; - criar mensagens de erro úteis;
- diagnosticar problemas sem alterar comportamento do programa.
Traceback
Quando ocorre erro, Python mostra um traceback.
def dividir(a, b):
return a / b
dividir(10, 0)
Erro:
ZeroDivisionError: division by zero
Leia de baixo para cima para encontrar o tipo do erro e a mensagem. Depois leia a pilha para entender o caminho até a falha.
Erros Comuns
NameError
print(nome)
O nome não foi definido.
TypeError
"idade: " + 30
Operação entre tipos incompatíveis.
ValueError
int("abc")
Tipo correto, valor inválido.
KeyError
usuario = {"nome": "Ana"}
print(usuario["idade"])
Chave inexistente.
IndexError
valores = [10]
print(valores[3])
Índice fora da lista.
Debug com Print
print pode ajudar em estudo e investigação rápida.
def calcular_total(preco, quantidade):
print("DEBUG:", preco, quantidade)
return preco * quantidade
Remova prints temporários antes de finalizar. Em código mantido, prefira logs.
Breakpoint
breakpoint() abre o depurador.
def calcular_total(preco, quantidade):
breakpoint()
return preco * quantidade
calcular_total(10, 3)
Comandos úteis no depurador:
n: próxima linha;s: entrar na função;c: continuar;p variavel: imprimir variável;q: sair.
Logging
logging registra eventos com níveis.
import logging
logging.basicConfig(level=logging.INFO)
logging.debug("Detalhe técnico")
logging.info("Processo iniciado")
logging.warning("Situação inesperada")
logging.error("Erro ao processar")
logging.critical("Falha crítica")
Exemplo em função:
import logging
logger = logging.getLogger(__name__)
def processar_pedido(pedido_id: int) -> None:
logger.info("Processando pedido %s", pedido_id)
Use placeholders do logging em vez de f-string quando possível, porque o logging pode adiar a formatação.
Mensagens de Erro Úteis
Ruim:
raise ValueError("Erro")
Melhor:
raise ValueError("preco deve ser maior ou igual a zero")
Com contexto:
def calcular_desconto(preco: float, desconto: float) -> float:
if desconto < 0 or desconto > 1:
raise ValueError(f"desconto deve estar entre 0 e 1. Recebido: {desconto}")
return preco * (1 - desconto)
Reproduzindo Problemas
Antes de corrigir:
- Identifique entrada que gera erro.
- Reduza o caso ao mínimo.
- Confirme que o erro acontece de forma repetível.
- Escreva um teste ou exemplo que falha.
- Corrija.
- Rode novamente.
Esse processo evita correções por tentativa.
Diagnóstico de Bugs Lógicos
Nem todo bug gera exceção.
Exemplo:
def aplicar_desconto(preco, desconto):
return preco * desconto
Se desconto = 0.10, o resultado deveria ser 90% do preço, não 10%.
Correção:
def aplicar_desconto(preco, desconto):
return preco * (1 - desconto)
Bugs lógicos exigem exemplos, testes e comparação com resultado esperado.
Boas Práticas
- Leia o erro antes de mudar código.
- Reproduza o problema com entrada mínima.
- Use
breakpointquando prints ficarem confusos. - Use logs para eventos importantes.
- Não esconda exceções com
except Exception: pass. - Mensagens de erro devem orientar correção.
- Transforme bug corrigido em teste quando possível.
Checklist de Proficiência
Você domina este tópico quando consegue:
- explicar um traceback;
- identificar erros comuns pelo tipo;
- usar
breakpoint; - configurar logging básico;
- criar mensagens de erro claras;
- reproduzir um bug com exemplo mínimo;
- diferenciar exceção de bug lógico.
Exercícios
- Crie exemplos que gerem
NameError,TypeError,ValueError,KeyErroreIndexError. - Use
breakpointpara inspecionar uma função. - Troque prints de depuração por logs.
- Corrija uma função com bug lógico e escreva o caso esperado.
- Crie uma exceção com mensagem clara para entrada inválida.
Aprofundamento Complementar
Diagnóstico com hipótese
Depurar bem não é alterar código aleatoriamente. Use hipóteses:
- O erro acontece com qualquer entrada ou uma entrada específica?
- O dado chega correto na função?
- O valor muda onde não deveria?
- A exceção é causa ou consequência?
- O comportamento mudou após qual alteração?
Logs com contexto
Log útil tem contexto suficiente.
logger.info("pedido_processado", extra={"pedido_id": pedido_id, "total": total})
Mesmo em logging simples, inclua identificadores: usuário, pedido, arquivo, linha, etapa ou comando.
Níveis de log
DEBUG: detalhe para investigação.INFO: evento normal importante.WARNING: situação inesperada, mas recuperável.ERROR: falha de operação.CRITICAL: falha grave do sistema.
Bug intermitente
Quando um bug aparece às vezes, investigue:
- ordem de execução;
- estado compartilhado;
- arquivo reaproveitado;
- dependência externa;
- data e hora;
- aleatoriedade;
- concorrência;
- cache.
Exercícios extras
- Adicione logs com contexto a uma função de processamento.
- Classifique cinco mensagens entre debug, info, warning, error e critical.
- Reproduza um bug usando entrada mínima.
- Use
breakpointpara verificar uma variável dentro de loop. - Escreva um checklist de diagnóstico para seus próprios projetos.