Introdução
Na programação de computadores, depuração (debugging) é o processo essencial de encontrar e resolver defeitos ou "bugs" que impedem um programa de operar corretamente. Embora os bugs sejam uma parte inevitável do desenvolvimento de software, o Python oferece um conjunto poderoso de ferramentas para ajudar você a diagnosticá-los e corrigi-los de forma eficiente.
Neste laboratório, você aprenderá várias técnicas fundamentais de depuração em Python. Cobriremos como:
- Levantar e tratar exceções manualmente para controlar o fluxo do programa durante erros.
- Capturar tracebacks de erro detalhados como strings para fins de registro (logging).
- Usar asserções (assertions) como verificações de sanidade para detectar erros lógicos precocemente.
- Implementar um sistema de registro (logging) flexível para rastrear a execução do seu programa e diagnosticar problemas sem interromper seu fluxo.
Disparando Exceções (Raising Exceptions)
Nesta etapa, você aprenderá a acionar exceções manualmente usando a instrução raise. Exceções são uma forma de sinalizar que ocorreu um erro. Uma instrução raise consiste na palavra-chave raise, uma chamada à função Exception(), e uma string de mensagem de erro útil passada para Exception().
É uma prática comum levantar exceções dentro de uma função quando seus pré-requisitos não são atendidos e, em seguida, tratar essas exceções no código que chama a função usando blocos try e except.
Nota: Se você não está familiarizado com o uso do WebIDE (semelhante ao VS Code), aprenda primeiro neste laboratório.
Vamos tentar isso com um exemplo.
- Abra o arquivo
raise_exception.pyno explorador de arquivos à esquerda. - Adicione o seguinte código ao arquivo. Este código define uma função
box_printque levanta exceções para argumentos inválidos e, em seguida, chama esta função com entradas válidas e inválidas, capturando as exceções.
def box_print(symbol, width, height):
if len(symbol) != 1:
raise Exception('Symbol must be a single character string.')
if width <= 2:
raise Exception('Width must be greater than 2.')
if height <= 2:
raise Exception('Height must be greater than 2.')
print(symbol * width)
for i in range(height - 2):
print(symbol + (' ' * (width - 2)) + symbol)
print(symbol * width)
## Handle exceptions when calling the function
for sym, w, h in (('*', 4, 4), ('O', 20, 5), ('x', 1, 3), ('ZZ', 3, 3)):
try:
box_print(sym, w, h)
except Exception as err: ## Catch exception and print error message
print('An exception happened: ' + str(err))
- Agora, execute o script a partir do terminal para ver como as exceções são levantadas e tratadas.
python3 raise_exception.py
Você verá a seguinte saída. As duas primeiras chamadas a box_print são bem-sucedidas, enquanto as duas últimas falham, acionando o bloco except para imprimir as mensagens de erro personalizadas.
****
* *
* *
****
OOOOOOOOOOOOOOOOOOOO
O O
O O
O O
OOOOOOOOOOOOOOOOOOOO
An exception happened: Width must be greater than 2.
An exception happened: Symbol must be a single character string.
Obtendo o Traceback como String
Quando ocorre uma exceção não tratada, o Python exibe um traceback (rastreamento de pilha), que é um relatório detalhado das chamadas de função que levaram ao erro. Às vezes, você deseja tratar a exceção de forma elegante, mas ainda assim registrar o traceback completo para depuração posterior. O módulo traceback permite fazer isso.
Nesta etapa, você aprenderá a usar traceback.format_exc() para capturar o traceback como uma string e salvá-lo em um arquivo.
- Abra o arquivo
get_traceback.pyno explorador de arquivos. - Adicione o seguinte código. Este script importa o módulo
traceback, em seguida, usa um blocotry...exceptpara capturar uma exceção. Dentro do blocoexcept, ele grava o traceback completo em um arquivo chamadoerrorInfo.txt.
import traceback
try:
raise Exception('This is the error message.')
except:
with open('errorInfo.txt', 'w') as error_file:
error_file.write(traceback.format_exc()) ## Write traceback to file
print('The traceback info was written to errorInfo.txt.')
- Execute o script no terminal.
python3 get_traceback.py
O script imprimirá uma mensagem de confirmação:
The traceback info was written to errorInfo.txt.
- Agora, verifique o conteúdo do arquivo recém-criado
errorInfo.txt. Você pode abri-lo no explorador de arquivos ou usar o comandocatno terminal.
cat errorInfo.txt
O arquivo conterá o traceback completo, semelhante a este:
Traceback (most recent call last):
File "/home/labex/project/get_traceback.py", line 4, in <module>
raise Exception('This is the error message.')
Exception: This is the error message.
Esta técnica é extremamente útil para registrar erros em aplicações de produção sem travar o programa.
Usando Assertivas (Assertions)
Assertivas são verificações de sanidade para garantir que seu código não esteja fazendo algo obviamente errado. Uma instrução assert verifica se uma condição é verdadeira. Se a condição for falsa, ela levanta uma AssertionError, que idealmente deve travar seu programa. Essa abordagem de "falhar rápido" (fail-fast) ajuda você a identificar a causa raiz de um bug mais rapidamente.
Uma instrução assert consiste na palavra-chave assert, uma condição a ser verificada e uma mensagem de erro opcional.
Nesta etapa, você usará uma assertiva para validar o estado de um programa.
- Abra o arquivo
use_assertions.pyno explorador de arquivos. - Adicione o seguinte código. Ele verifica o status de
pod_bay_door_status. A primeira assertiva passa silenciosamente, mas a segunda falhará e levantará umaAssertionError.
## assert statement: check condition, raise AssertionError if False
pod_bay_door_status = 'open'
assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' ## Passes
pod_bay_door_status = 'I\'m sorry, Dave. I\'m afraid I can\'t do that.'
assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' ## Raises AssertionError
- Execute o script no terminal.
python3 use_assertions.py
Como a segunda assertiva falha, o programa travará e você verá uma AssertionError com sua mensagem personalizada.
Traceback (most recent call last):
File "/home/labex/project/use_assertions.py", line 6, in <module>
assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".'
AssertionError: The pod bay doors need to be "open".
Diferentemente das exceções, você não deve tratar assertivas com try...except. Uma AssertionError sinaliza um bug no programa que precisa ser corrigido. Também vale a pena notar que as assertivas podem ser desativadas globalmente executando o Python com a flag -O (otimizar), portanto, elas não devem ser usadas para validação de entrada que deve ser sempre aplicada.
Implementando o Logging
Embora as instruções print() possam ser usadas para depuração (debugging), uma abordagem mais poderosa e flexível é usar o módulo logging nativo do Python. O registro de logs permite rastrear eventos enquanto seu programa é executado e categorizar mensagens por severidade.
Nesta etapa, você adicionará registro de logs a um programa para ajudar a diagnosticar um bug.
- Primeiro, abra o arquivo
factorial_log.pyno explorador de arquivos. - Adicione o seguinte código. Este programa tenta calcular o fatorial de um número, mas contém um bug. Adicionamos chamadas
logging.debug()para rastrear os valores das variáveis em cada etapa. A funçãologging.basicConfig()configura o sistema de logging para exibir mensagens de nívelDEBUGe superior.
import logging
logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s')
logging.debug('Start of program')
def factorial(n):
logging.debug('Start of factorial(%s)' % (n))
total = 1
for i in range(1, n + 1):
total *= i
logging.debug('i is ' + str(i) + ', total is ' + str(total))
logging.debug('End of factorial(%s)' % (n))
return total
print(factorial(5))
logging.debug('End of program')
- Execute o script no terminal.
python3 factorial_log.py
Você verá a saída detalhada do log intercalada com a saída regular do programa.
%(asctime)s - DEBUG - Start of program
%(asctime)s - DEBUG - Start of factorial(5)
%(asctime)s - DEBUG - i is 1, total is 1
%(asctime)s - DEBUG - i is 2, total is 2
%(asctime)s - DEBUG - i is 3, total is 6
%(asctime)s - DEBUG - i is 4, total is 24
%(asctime)s - DEBUG - i is 5, total is 120
%(asctime)s - DEBUG - End of factorial(5)
120
%(asctime)s - DEBUG - End of program
Ao examinar as mensagens de log, você pode ver claramente o valor de i e total em cada iteração do loop, o que é uma maneira poderosa de entender o fluxo do programa e encontrar bugs.
Configurando o Comportamento do Logging
O módulo logging é altamente configurável. Você pode controlar o nível de severidade das mensagens a serem exibidas, desativar o registro de logs completamente ou redirecionar as mensagens de log para um arquivo em vez da tela.
Níveis de Registro de Logs (Logging Levels)
Existem cinco níveis de registro de logs padrão, cada um com uma função correspondente:
| Nível | Função de Registro (Logging Function) | Descrição |
|---|---|---|
DEBUG |
logging.debug() |
Para detalhes pequenos, úteis apenas ao diagnosticar problemas. |
INFO |
logging.info() |
Para registrar eventos gerais ou confirmar que as coisas estão funcionando como esperado. |
WARNING |
logging.warning() |
Para indicar um problema potencial que não impede a execução do programa. |
ERROR |
logging.error() |
Para registrar um erro que fez uma operação específica falhar. |
CRITICAL |
logging.critical() |
Para um erro fatal que está prestes a causar a terminação do programa. |
Quando você define um nível de registro de logs em basicConfig, o Python exibirá mensagens nesse nível e em todos os níveis superiores. Por exemplo, definir level=logging.INFO mostrará mensagens INFO, WARNING, ERROR e CRITICAL, mas não DEBUG.
Desativando o Registro de Logs
Após a depuração, você pode querer desativar todas as mensagens de log sem remover as chamadas de logging do seu código. Você pode fazer isso com logging.disable(). Ele aceita um nível como argumento e desativa todas as mensagens de log nesse nível e abaixo. Por exemplo, logging.disable(logging.CRITICAL) suprimirá todas as mensagens de log.
Registro de Logs em um Arquivo
Em vez de imprimir os logs no console, você pode salvá-los em um arquivo passando o argumento de palavra-chave filename para logging.basicConfig().
Vamos praticar isso.
- Abra o arquivo
configure_logging.py. - Adicione o seguinte código. Ele configura o registro de logs para gravar todas as mensagens de nível
DEBUGe superior em um arquivo chamadomyProgramLog.txt.
import logging
## Configure logging to write to a file
logging.basicConfig(filename='myProgramLog.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('This is a debug message.')
logging.info('This is an info message.')
logging.warning('This is a warning message.')
- Execute o script no terminal.
python3 configure_logging.py
Desta vez, você não verá nenhuma saída no terminal.
- Verifique o conteúdo do arquivo
myProgramLog.txt.
cat myProgramLog.txt
Você verá que todas as mensagens de log foram gravadas no arquivo, completas com carimbos de data/hora (timestamps) e níveis de severidade.
2023-10-27 10:30:00,123 - DEBUG - This is a debug message.
2023-10-27 10:30:00,123 - INFO - This is an info message.
2023-10-27 10:30:00,123 - WARNING - This is a warning message.
Isto conclui nosso passeio pelas técnicas básicas de depuração em Python.
Resumo
Neste laboratório, você aprendeu e praticou várias técnicas essenciais de depuração (debugging) em Python. Você começou usando a instrução raise para criar e disparar exceções personalizadas, e as tratou com blocos try...except. Em seguida, aprendeu a capturar um traceback de exceção completo como uma string usando traceback.format_exc() para fins de registro de logs.
Em seguida, você explorou as instruções assert como uma maneira de realizar verificações de sanidade (sanity checks) e "falhar rapidamente" (fail fast) quando seu programa entra em um estado inesperado. Por fim, você se aprofundou no módulo logging, aprendendo a configurá-lo para exibir mensagens, controlar a saída com diferentes níveis de registro de logs e gravar logs em um arquivo para registros persistentes.
Essas habilidades são fundamentais para escrever aplicações Python robustas, de fácil manutenção e mais fáceis de depurar.



