Depuração (ou debugging) é o processo de localizar, analisar e corrigir erros em um programa. Existem dois tipos principais de erros:
n-1 ao invés de n em um cálculo).Um depurador permite ao programador observar a execução passo‑a‑passo, inspecionar variáveis e controlar o fluxo. As principais funcionalidades são:
pdb e IDEsO módulo pdb já vem com a instalação padrão do Python. Ele funciona via linha de comando e requer conhecimento dos comandos (break, next, step, continue, etc.).
IDE’s como PyCharm (ou “Pytar” mencionado na aula) oferecem depuradores gráficos, facilitando a inserção de breakpoints com cliques, visualização de variáveis e controle visual de step over/into.
O código usado na demonstração contém três funções:
def h(n):
print("start H")
print(1 / n) # pode gerar divisão por zero
print(n)
def g(n):
print("start G")
h(n-1)
print(n)
def f(n):
print("start F")
g(n-1)
print(n)
f(2)
Ao executar f(2) ocorre ZeroDivisionError porque h recebe n = 0. O traceback mostra a cadeia de chamadas, mas não revela por que n chegou a zero.
Usando o depurador:
print("start F").g(n-1) e, em seguida, Step Into para entrar em g.n foi decrementado para 1, e ao entrar em h ele se torna 0.h, o erro de divisão por zero é disparado.Assim, o depurador permite identificar que o problema está na lógica de decremento (n-1) antes da chamada a h.
1. Conceitos básicos de depuração
2. Ferramentas e técnicas de depuração
3. Depurador em Python
pdb (linha de comando)4. Exemplo prático apresentado
f, g, hn = 0)5. Dicas de boas práticas
Resposta correta: C) Erro crítico impede a continuação da execução (ex.: divisão por zero); erro lógico permite a execução, mas produz resultado incorreto.
Erros críticos lançam exceções que interrompem o programa, enquanto erros lógicos resultam em saídas inesperadas sem interromper a execução.
def h(n):
return 10 / (n - 2)
def g(n):
return h(n - 1)
def f(n):
return g(n - 1)
f(4)
Qual será a primeira linha onde o depurador deve parar (breakpoint) para identificar a origem da ZeroDivisionError?
Resposta correta: A) Na linha return 10 / (n - 2) dentro de h.
O erro ocorre quando n vale 2 dentro de h. Colocando o breakpoint nessa linha permite observar o valor de n antes da divisão.
n antes da exceção, sem entrar nas chamadas de função internas?
def h(n):
print("start H")
print(1 / n) # pode gerar divisão por zero
print(n)
def g(n):
print("start G")
h(n-1)
print(n)
def f(n):
print("start F")
g(n-1)
print(n)
f(2)
Resposta correta: C) Breakpoint em h, Step Over até a linha da divisão, observar n
Colocando o breakpoint exatamente na função que gera a exceção e usando Step Over permite avançar até a instrução problemática mantendo o valor de n visível.
n nunca será zero antes da divisão. Qual das alternativas abaixo descreve a melhor estratégia usando recursos do depurador?
Resposta correta: A) Inserir um breakpoint condicional em h com a condição n == 0 e, ao disparar, alterar n para 1.
Um breakpoint condicional permite interromper a execução somente quando a condição problemática ocorre, possibilitando a correção imediata do valor sem precisar modificar o código fonte.
Apenas de um pouquinho sobre a depuração de programas.
Olá pessoal, bem vindos novamente a nossa disciplina de algoritmos e programação de computadores 1 para o Nvespe.
Nessa nossa última videoaula desse curso, a gente vai aprender um pouquinho sobre depuração de programas.
Então vamos entender um pouquinho como a gente faz para depurar os nossos programas, para entender se existem erros ou existem problemas de execução que podem estar enviabilizando o resultado correto ou esperado de um determinado programa.
E a gente vai ver então que existem ferramentas, existem técnicas que podem auxiliar o programador, o desenvolver do software para detectar esses possíveis erros no programa e facilitando também a manutenção e correção desses problemas.
Bom, então a depuração de programas consiste então num processo de encontrar e reduzir erros em implementações e em programas.
Os erros podem impossibilitar que o programa continue em sua execução, caso seja um erro muito grave, por exemplo, uma divisão por zero ou, por exemplo, não tem encontrado um arquivo para leitura entre vários outros erros que realmente não permitem que o programa continua a execução.
E existem também uma outra classe de erros que fazem com que o programa gere como sair da um resultado correto.
Então, por exemplo, você quer calcular a potência de um número e, ao invés de você multiplicar o número pelo valor da potência, você multiplica para um valor menos um, por exemplo.
Então, é um erro que fica mascarado, então o programa vai gerar como sair de um resultado, mas esse resultado vai ser correto, não vai ser o resultado esperado.
Para ambos os tipos de erros que eu falei aqui, a depuração de programas pode ser utilizada para encontrar os erros, encontrar onde estão esses problemas.
E aí, com isso, uma vez é ter que estar a do esse problema, o programador pode lá e fazer a correção.
Então, os depuradores são ferramentas que auxilia o programador, essas ferramentas permitem que o programador consiga monitorar a execução de um programa, então, eles permitem que a instrução, a instrução, o programador possa ir verificando o resultado de cada uma dessas instruções.
Ele pode também parar a execução em um ponto do tempo lá da execução.
Então, a invés de ter que aguardar toda a execução daquele programa, ele pode detectar logo no início aquele erro e finalizar aquele programa e já encontrar o erro.
Ele pode reiniciar o programa, pode também ativar pontos de parada, então, ele pode fazer com que o programa execute até uma determinada linha do programa e a partir daquela linha, ele vai analisar o estado do programa e, depois, a partir daí, executar a linha, a linha aquelas instruções, procurando encontrar o erro.
E alterar a área de memória durante a execução.
Então, algumas ferramentas de depuração permitem acesso, também, a memória interna do computador, mostrando a liqueção as variáveis e seus respectivos valores que foram setados até aquele momento da execução do programa.
E aí, o programador pode analisar esses valores para verificar se estão corretos ou não, entre várias outras funcionalidades que os depuradores oferecem para o programador.
No caso da linguagem Python, pessoal, quando vocês baixam o kit, de desenvolvimento, você recebe também um depurador que é o PDB.
Esse PDB vai estar disponível lá na sua máquina, uma vez que você tenha instalada a linguagem Python.
Então, ela já vem em clúsia na biblioteca padrão.
Você pode usar esse depurador PDB.
O único coisa que ele vai ser por liante comando, então você tem que lembrar de alguns comandos básicos para poder utilizar esse depurador.
Mas existem também IDS de desenvolvimento que a maioria contém também um depurador mais visual, mais fácil de ser utilizado.
E por exemplo, a IDS que a gente está utilizando aqui na disciplina, o Pytar, ela já vem com um depurador embutido e você pode usar aquele depurador para analisar o seu código.
O que a gente vai fazer aqui na sua vida, então vamos mostrar para vocês como o depurador do Pytar funciona, mostrando algumas funcionalidades mais básicas.
Para isso, a gente vai utilizar esse código que está aqui, que ele tem um erro, ele tem um problema onde quando a gente vai executar esse código passando aqui f2, que é a execução do programa, em algum momento ele vai gerar um erro, vai gerar um problema nessa execução.
E nessa video aula, nessa demonstração, vou mostrar para vocês como a gente faz para encontrar esse erro.
Então vamos lá.
Aqui, pessoal, eu já tenho implementado aquele programa na minha ID, então reparem que eu tenho três funções, H, G e F, e eu estou chamando aqui o F, a função F, com o argumento 2, então esse 2 vai ser passado aqui para o N, e aí a função F chama a função G, a função G chama a função H e H faz esse cálculo que está aqui.
Então se eu executar esse programa de uma vez, olha só, ele vai gerar um erro aqui, se a gente analisar, reparem que eu estou chamando o F de 2, então como isso aqui, pessoal, esse traceback que está aqui no meu interpretador, com isso já fica relativamente fácil de a gente entender onde está o problema, o qual que é o problema aí do nosso código, então reparem que esse texto que foi impresso aqui foi o nosso interpretador que gerou para a gente.
Na verdade, a gente tem aqui no nosso programa alguns prints que são start, F, start, G, start, H e é o que está sendo impresso aqui em cima, está na empreita, o programa realmente está sendo executado até a função H, então F chama G, chama O H, e aqui na função start H na função H, é onde está ocorrendo o erro, então esse traceback aqui é o que o interpretador nos indicou, e ele imprime para a gente toda a pilha de execução do programa, então ele coloca aqui, e tem entre parentes, o most, o recentral last, então ele vai meio que de cima para baixo, ele vai apresentando aí todo o traço de execução do programa nosso, então reparem que ele começa aqui na linha 16, onde a nossa linha 16 é essa que está aqui, chamada a função F, passando o argumento 2, depois ele tem aqui a linha 13, então a linha 13 é onde a gente está chamando a função G, depois ele vem para a linha 8, que é a, quer dizer, então a linha 13 ele chamou a função G, entrou aqui na função G começou a executar a ele imprime lá a execução da chamada a função H, que está na linha 8, e da linha 8 ele imprime aqui o da linha 3, então ele entrou na linha H, ele entrou na função H, na função H ele começou a executar, e aí ele imprime aqui o a linha 3, e é onde ele apresenta aqui o problema que deu, então aqui, eu vou de divisão por 0, então na verdade ele está imprimindo para a gente um erro que é a divisão por 0, que ocorreu na linha 3, e a linha 13 é onde eu tenho realmente um print, onde eu passo aqui um erro dividido por N, então provavelmente esse N aqui, provavelmente não, né, certeza que esse N aqui é o denominador, ele é zero, ele está fazendo uma divisão de 1 por 0, por isso que ele imprimiu aqui divisão por 0, bom, mas existe a possibilidade, isso aqui que eu mostrei para vocês, pessoal, ainda não é o denominador, isso aqui é simplesmente o que o nosso interpretador gera, uma vez que ele detecta um erro, se a gente quer, por exemplo, detectar coisas mais detalhadas, então por exemplo, supondo que a gente olha esse traceback, e a gente não consiga entender ainda, por que esse N virou zero, a gente pode usar um depurador, e aí então é onde eu vou explicar para vocês, como que ele funciona, o depurador, ele está aqui em run, a gente consegue executar o programa no modo de debug, de depuração, executando esse código aqui de depuração, simplesmente no jeito que está, ele vai fazer execução de todo o programa, e aí ele para exatamente onde deu problema, tá bom, então fazendo a execução da depuração sem nada, do jeito que está, ele executa todo o programa e ele para exatamente onde ele encontrou o erro, exatamente onde está aqui, essa é a exceção, aqui a gente, então reparem que essa janelinha, essa janelinha já de debug, de depuração, tá, e ele já mostra aqui que na nossa memória a gente tem a variável N, que está citada como zero, então realmente esse N aqui ele está sendo usado para dividir um N, é zero, então por isso que deu problema, e aí aqui no console a gente tem também o resultado aqui da execução, então a gente inicializou chamou a função f, ele em primeiro start f, depois start g, start h, e aí ele já imprimiu aqui aquele traceback, que é exatamente aquilo que a gente viu, anteriormente, só que um pouco mais de detalhes, até chegar na divisão por zero, bom, mas ainda não é o que a gente procura, a gente quer saber por que o N virou zero, reparem que aqui então ele para já com N igual a zero, e a gente não quer isso, a gente quer entender antes, o por que aquele N virou zero até aquele ponto, tá, então para isso, a gente tem alguns outros comandos que a gente pode inserir, que é por exemplo a inserção de um checkpoint, um checkpoint indica que quando a gente rodar o programa em modo de debug, ele vai executar até aquela linha de checkpoint, então supondo que a gente quer inserir um checkpoint, exatamente aqui no start f da função f, quer dizer aqui da linha 12, então eu só eu vim aqui aplicar na lateral aqui do lado do número da linha, esse ver ponto vermelho aqui é o checkpoint, tá, agora quando eu mando executar novamente em modo debug, repara aquele para, exatamente naquela linha de checkpoint, então até aqui ainda não ocorreu o erro, então ele chamou f de dois, executou aqui a chamada a função s, e aqui ele parou no start f, no print aqui do start f, repara aqui no console, também ele ainda não imprimiu nada, porque ainda não imprimiu o que está aqui, tá, ele ainda está guardando as minhas instruções, e aí agora aqui pessoal, eu tenho alguns botões que estão aqui que são bem interessantes, um deles que eu vou falar pra vocês é o step over, o step over significa que eu estou mandando o debugador executar aquela instrução sem entrar nela, quer dizer sem divulgar o que está dentro dela, então eu vou clicar aqui em step over, ele vai simplesmente executar aquela instrução e vai para a linha de baixo, repara aqui no meu console, ele imprimiu o start f, que é o resultado da função print, tá, voltando aqui, ele agora está guardando, eu dá um comando pra essa próxima instrução aqui da linha 13, se eu rodar de novo o step over pessoal, ele vai executar o que está dentro da função g, sem detalhes, ele vai executar tudo que está lá dentro e vai vim para a próxima linha, repara aqui, quando eu executo isso, ele vai gerar o erro pra gente, porque a gente sabe que a função f está chamando a g, que está chamando a h e é onde está ocorrer no erro, né, então se eu executar o step over, a gente não vai saber o que aconteceu dentro dessa execução aí da função g, tá, então para isso a gente usa um outro comando que é o step into, o step into significa que eu quero analisar o conteúdo dessa função g, então com isso eu vou apertar o step into, ele foi para dentro da função g, e lá dentro da função g ele está guardando a próxima instrução, o meu comando, pra saber o que eu quero fazer, tá, bom, vou colocar um step over novamente aqui, pra ele imprimir o string start g, então ele imprimiu, até não consolha aquele, já imprimiu o start g, tá, reparem que o n, ele foi decrementado em uma unidade, então o n, a gente tinha passado aqui 2, e aqui o g está passando com o n menos 1, então reparem que aqui o n tem valor 2, que a gente pode visualizar tanto aqui, como aqui em cima, tá, e agora aqui no, na chamada do h, a gente pode dar um step into novamente, com isso ele vai entrar dentro da função h, lá dentro da função h, a gente pode verificar que o escopo, né, da variável n, agora foi alterado novamente, então o n agora vale zero, porque, porque a gente chamou a função h com n menos 1, o n vale 1, agora estou chamando com um n menos 1, então o n agora vira zero, e aí lá dentro a gente pode rodar um step over de novo, pra ele imprimir o start g, então aqui no console ele imprimir o start g, e agora, exatamente aqui é onde a gente consegue detectar o erro, né, porque a gente vê que o n vale zero, e aqui a gente está fazendo uma divisão por n, tá, então aqui tanto faz, eu colocar um step over, ou um step into, tá, ele vai apresentar aqui um erro pra você, na verdade ele voltou aqui pra essa função, porque ele tá retornando da função com uma exceção, né, que é aquele erro lá que deu de divisão por zero, então se eu rodar novamente aqui, ele tá saindo, tá saindo das funções, que ele tá voltando na execução do da pilha lá de chamada das funções, então rodando novamente, ele volta lá pro programa principal, aqui ainda ele não mostrou na tela o erro que deu, tá, mas ele tá voltando lá da execução, da retorno, né, das funções h e g, e agora aqui do erro ele também retornou, apertando novamente o step over, aí sim ele apresenta pra você a exceção, tá, então aqui ele apresenta aqui a divisão por zero, exatamente esse retorno, né, da, que ele fez lá das chamadas das funções, ele impreme na tela e, e aqui ele mostra também a exceção que foi gerada lá execução, e por fim, mais uma vez ele finaliza aqui a execução do programa, tá certo? Uma outra funcionalidade interessante é quando você coloca o cursor numa, numa linha, por exemplo, você pode mandar executar, é você pode mandar executar até aquela linha, né, na verdade eu preciso primeiro rodar aqui com o chatpoint, tá, então ele vai parar aqui, e agora se eu coloco o cursor, por exemplo, aqui ele, a gente tem a possibilidade de rodar até o cursor, então até ele encontrar o cursor, quer dizer esse ponto aqui que tá clica, pescando, ele vai executar, tá, então ele veio, fez execução de tudo, chegou aqui, aí ele tá guardando as minhas instruções, então aí é o mesmo processo, né, então ele vai voltando, já que deu o erro, né, até que chega o momento que ele gera a exceção pra você, muito bem, então essa daqui foi a nossa videoaula sobre depuração de programas, espera que vocês possam ter entendido um pouquinho como que funciona, né, a depuração, e procurem exercitar, né, o depurador com os programas de vocês, pra vocês entenderem aí como que eles funcionam, que são bastante úteis, tá, então eu agradeço mais uma vez pela atenção de vocês, essa foi a nossa última videoaula, desse curso, e a gente se vê no próximo o bem-mestre com a continuação do curso, por meio do módulo 2, dá disciplina, obrigado e até mais.