PYTHON DEBUGGER!
Uma Breve Introdução
O que é isto de
Debugger e o acto de fazer
debugging, perguntam vocês.
O acto de Debugging é pura e simplesmente o acto de procurar e corrigir bugs num código (e existem sempre bugs, vocês podem é não ter reparado neles

).
Primeiro, quero notar que utilizar o debugger do Python não é talvez tão usual como o de, por exemplo, C, pois quando um programa em Python crasha de uma forma não muito bonita, normalmente deita sempre cá para fora as mensagens de erro.
Essas mensagens, por vezes permite-nos saber e corrigir os erros mais básicos.
Exemplo:
GeSHi (python):
numero = 1
numero = numero + 10
print "O Numero e: " + numero
Created by GeSHI 1.0.7.20
Isto deverá de dar um erro no print, pois a variável "numero" é um integer, e não se pode juntar uma string a um integer, sem antes o converter também para string.
E o Output, certo como um relógio:
Traceback (most recent call last):
File "exemplo1.py", line 5, in <module>
print "O Numero e: " + numero # Vai dar um erro porque "numero" nao e string
TypeError: cannot concatenate 'str' and 'int' objects
O Debugging pode ser feito de várias maneiras, como por exemplo, através de "print variavel".
Exemplo:
GeSHi (python):
numero = 1
print ">> numero = %s" % numero # Neste momento "numero = 1"
numero = numero + 10
print ">> numero = %s" % numero # Neste momento "numero = 11"
print "O Numero final e: %s" % numero # E este e o vosso output final (aquilo que ira ficar no programa final)
Created by GeSHI 1.0.7.20
O output deste código seria:
>> numero = 1
>> numero = 11
O Numero final e: 11
Neste caso, tomamos como valor a assinalar um print de debugging o símbolo ">>".
No final, quando já tivessem acabado de fazer o debugging, simplesmente teriam que comentar essas linhas, para as mensagens desaparecer. E ficaria assim:
GeSHi (python):
numero = 1
#print ">> numero = %s" % numero
numero = numero + 10
#print ">> numero = %s" % numero
print "O Numero final e: %s" % numero
Created by GeSHI 1.0.7.20
Sendo que o output passaria a ser simplesmente:
O Numero final e: 11
Até aqui tudo bem.
Mas quando se começa a ter programas cada vez mais complexos, começa a não dar muito jeito ter prints por tudo quando é lado, principalmente se a vossa aplicação for uma aplicação de terminal, em que fica tudo completamente misturado, o output de debugging e o output do programa em si.
Não seria bom se houvesse um programa que podesse facilitar esse trabalho? NÃO SERIA!?!?! (não têm escolha)
Eis que entra o tão famoso debugger.
Um debugger é nada mais, nada menos que um programa que facilita o acto de debugging (óbvio...).
Com um debugger pode-se, por exemplo, parar o programa a qualquer momento, ou alterar um valor de uma variável enquanto o programa está a correr.
O Python tem um debugger incorporado, chamado Pdb (Python DeBugger. obviamente), apesar de existirem outros (como o
Pydb). No entanto, não irei falar nestes por este tutorial é apenas dedicado a uma introdução (em relação ao Pydb, têm lá um link para um video de demonstração de 13 minutos (acho eu), do Pydb a correr em Emacs, estando o vídeo alojado Showmedo).
Existem várias formas de invocar o pdb, sendo a mais simples o invocar numa consola, juntamente com o nome do ficheiro com o qual querem fazer o debugging:
rolando@main-computer:~/Programacao/Python/meus_scripts/tutorial_debugging$ pdb exemplo1.py
E se tudo correr bem, isto é o que deverão de ver.
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo1.py(3)<module>()
-> numero = 1
(Pdb)
E o cursor deverá de estar à frente do
(Pdb) .
Outro método é invocar o pdb directamente através do código fonte do programa.
Acontece que o pdb contêm um módulo que pode ser usado como outro qualquer, utilizando o comando
import pdb .
Esse módulo contêm alguns métodos, mas só vou focar no set_trace() e no run(), que são métodos que vos colocam na prompt do pdb (como está acima).
O run() tem a seguinte sintaxe:
pdb.run(expressão_a_correr [, variáveis_globais [, variáveis_locais]])Como isto a ideia deste tutorial é para manter as coisas simples, vamos esquecer as partes das variáveis globais e locais.
O que o pdb.run faz é pura e simplesmente uma string como se fosse um comando de Python, dentro do pdb, para poderem analisar, por exemplo, uma função com calma.
Por exemplo,
pdb.run(funcao_teste("string")), permitia correr a função dentro do pdb.
O outro método, o set_trace(), apenas vos colocar dentro do pdb, naquela linha onde está o pdb.set_trace().
Isso é bom, por exemplo, se quisererem só fazer debugging a uma parte qualquer do programa, e não querem ter que caminhar dentro do pdb até essa linha.
Assim, basta só um pdb.set_trace() antes do espaço que querem fazer o debugging, e o pdb abre automaticamente.
Vamos desviar-nos do assunto do set_trace(), e do run(), para se ver como é que utiliza o pdb, depois dele nos colocar na prompt.
Temos aqui este código, que soma todos os números de 0 até um valor que vocês derem (estilo 1+2+3+4+5+6+7+8+9+10=55):
GeSHi (python):
#!/usr/bin/python
#import pdb
def soma_todos_numeros(numero):
#pdb.set_trace()
soma = 0
while numero > 0:
soma = soma + numero
numero = numero - 1
return soma
print "Bem-vindo ao programa que soma todos os numeros!"
print "Quer somar todos os numeros de 0 ate?"
n = raw_input("Numero: ")
total = soma_todos_numeros(int(n))
#pdb.run("total = soma_todos_numeros(int(n))")
print "A soma de todos e: %s" % total
Created by GeSHI 1.0.7.20
Reparem que os comandos do pdb estão comentados (são para os exemplos mais à frente

)
Vamos correr o programa só para ver se está tudo bem.
rolando@main-computer:~/Programacao/Python/meus_scripts/tutorial_debugging$ python exemplo2.py
Bem-vindo ao programa que soma todos os numeros!
Quer somar todos os numeros de 0 ate?
Numero: 10
A soma de todos e: 55
Cá está! Podemos ver que o programa está a funcionar bem. Não seria então necessário fazer debugging a ele, mas vamos fazer na mesma, para ficarem a perceber como é que ele funciona (pensem numa secção de debugging como uma conversa num café, entre vocês, o programa, e o programador que escreveu o programa).
Vamos então executar o pdb na shell:
rolando@main-computer:~/Programacao/Python/meus_scripts/tutorial_debugging$ pdb exemplo2.py
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(5)<module>()
-> def soma_todos_numeros(numero):
(Pdb)
Reparem na linha que está a negrito. Essa linha diz-vos a próxima linha que o pdb vai executar.
A primeira coisa a fazer é saber em que zona do ficheiro estão, utilizando o comando
list (ou simplesmente
l), para verem em que linha estão, e o que têm à vossa volta. (Podem também ver que na linha por cima da que está a negrito tem lá um "(5)", significando que estão na quinta linha)
Escrevam
list no prompt, e eis o que vos aparece:
(Pdb) list
1 #!/usr/bin/python
2
3 #import pdb
4
5 -> def soma_todos_numeros(numero):
6 #pdb.set_trace()
7 soma = 0
8
9 while numero > 0:
10 soma = soma + numero
11 numero = numero - 1
(Pdb)
Observamos que estámos de facto na linha 5 (o sinal -> indica obviamente a linha onde estão).
O comando
list imprime no ecrã as 11 linhas que estão à volta da linha onde estão (por default, podem alterar isto se quiserem).
Este comando deverá de ser familiar àqueles que já têm experiência no Gdb (Um debugger de C). De facto, existem comandos que são diferentes aos do Gdb, mas nesta introdução, todos os comandos deverão de reagir de forma semelhante no Gdb (penso eu, não tenho muita experiência com ele).
Para executarem o comando que está na linha onde estão (neste caso, o
def soma_todos_numeros(numero):) e passarem para o próximo comando, escrevam
next (ou
n), ou
step (
s).
Existe uma diferença entre o
next e o
step, mas já irei falar disso mais tarde.
(Pdb) next
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(15)<module>()
-> print "Bem-vindo ao programa que soma todos os numeros!"
(Pdb)
Tal como diz no prompt, estamos agora na linha 15 (podem também confirmar usando o
list) do ficheiro, que contêm um comando print.
Reparem que o print ainda não foi executado, mas será o próximo comando a ser executado, quando usar o
next, ou o
step.
Existe um atalho para não terem que andar sempre a escrever o mesmo comando.
Se o prompt do pdb estiver vazio e carregarem no Enter, ele irá repetir o último comando realizado (neste caso, o
next), por isso carregem na tecla Enter agora.
(Pdb)
Bem-vindo ao programa que soma todos os numeros!
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(16)<module>()
-> print "Quer somar todos os numeros de 0 ate?"
(Pdb)
Reparem que só depois de terem dito para o pdb avançar, é que o print foi executado.
Continuando...
(Pdb)
Quer somar todos os numeros de 0 ate?
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(18)<module>()
-> n = raw_input("Numero: ")
(Pdb)
Numero: 10
Temos na mesma que fazer todos os inputs para o programa.
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(20)<module>()
-> total = soma_todos_numeros(int(n))
(Pdb)
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(22)<module>()
-> print "A soma de todos e: %s" % total
(Pdb)
(Pequena nota: Reparem que ele não parou nos comments)
Prestem agora atenção para a diferença entre o
next e o
step.
Quando fizeram
next na linha que usava a função
soma_todos_numeros, o pdb não vos mostrou o que é que o Python andou a fazer lá para dentro dela.
Se quiserem ver o que se passa por dentro de funções (ou até mesmo de imports), têm que usar o
step.
Vamos sair do pdb, utilizando o comando
quit (ou
q), e voltarmos à linha do
total = soma_todos_numeros(int(n)), mas em vez de usar-mos o
next, vamos usar o
step e ver o que o Python anda para lá a fazer.
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(20)<module>()
-> total = soma_todos_numeros(int(n))
(Pdb) s
--Call--
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(5)soma_todos_numeros()
-> def soma_todos_numeros(numero):
(Pdb)
O pdb regressa novamente à linha 5 (usem o
list para verificarem isso).
Agora podem fazer várias coisas.
Podem usar o
next e o
step da mesma maneira que o têm usado até aqui, ou se quiserem podem automaticamente saltar até à linha de return que vai ocurrer, usando o comando
return (ou simplesmente
r).
Vamos então usar o
return, para ver como a função vai acabar.
(Pdb) return
--Return--
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(13)soma_todos_numeros()->55
-> return soma
(Pdb)
Cá está. Agora estamos na linha 13.
Vamos continuar com o
next (também podem usar o
step) para finalizar a função.
(Pdb) next
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(22)<module>()
-> print "A soma de todos e: %s" % total
(Pdb)
Que será o valor que a variável
total tem?
Para saber isso usamos o comando
print (ou só
p).
A sintaxe é simples:
print nome_variavel
(Pdb) print total
55
Mas imaginemos que nós queremos enganar o programa, para ver como ele iria reagir, e queremos mudar o valor da variável
total?
Para isso tem que se dar um comando directamente ao python, colocando um
! antes do comando. (Nota: Na verdade, qualquer comando não reconhecido pelo pdb é interpretando como sendo um comando de Python, como o comando
print atrás. O
! serve só para terem a CERTEZA que o comando vai ser interpretado pelo python e não pelo pdb)
Depois de colocarem o
!, é só escrevem o comando como se fosse um comando normal do python (que colocariam, por exemplo, no IDLE).
(Pdb) !total = 1
(Pdb) print total
1
(Pdb)
Podem ver que a variável
total passou de 55 a 1.
Se agora executar-mos o print que está no ficheiro, ele vai dar um valor diferente do da primeira vez.
(Pdb) next
A soma de todos e: 1
--Return--
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(22)<module>()->None
-> print "A soma de todos e: %s" % total
(Pdb)
E chegaram ao fim do programa. Para voltarem ao início do programa, para continuarem a fazer o debug, voltem a usar o comando
next ou
step, e o pdb colocava-vos automaticamente no início.
(Pdb) next
--Return--
> <string>(1)<module>()->None
(Pdb) next
The program finished and will be restarted
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(5)<module>()
-> def soma_todos_numeros(numero):
(Pdb)
E cá está o início.
Agora só vou falar de mais dois comandos, o
break (ou só
b) e o
continue (ou só
c).
Vamos começar com o
continue. Este comando faz com que o programa que está no pdb corra até ao fim, sem parar, EXCEPTO num breakpoint, que são colocado usando o comando
break.
Isto serve para que não tenham de estar sempre a fazer
next, até chegarem à parte que querem corrigir. Apenas coloquem um breakpoint, e fazam
continue até lá chegar. E depois o programa pára e voltam ao controlo do pdb.
A sintaxe do break é:
break numero_da_linha_do_ficheiro
Podem usar mais algumas coisas como nomes de funções e de ficheiros, mas isso já está fora da parte da introdução.
Se escreverem só
break, podem ver uma lista de todos os breakpoints que criaram na secção actual.
Voltando ao código inicial, digamos que queremos parar o programa duas vezes, na linha 7 (dentro da função
soma_todos_numeros) e na linha 20.
(Pdb) break 7
Breakpoint 1 at /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py:7
(Pdb) break 20
Breakpoint 2 at /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py:20
(Pdb) break
Num Type Disp Enb Where
1 breakpoint keep yes at /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py:7
2 breakpoint keep yes at /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py:20
(Pdb)
Podem ver que temos agora 2 breakpoints colocados no ficheiro. Agora se usar-mos o
continue, ele irá parar só nessas linhas.
(Pdb) continue
Bem-vindo ao programa que soma todos os numeros!
Quer somar todos os numeros de 0 ate?
Numero: 10
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(20)<module>()
-> total = soma_todos_numeros(int(n))
(Pdb)
Como podem ver, o pdb correu o programa como se ele tivesse a correr normalmente (não o parou a todas a linhas).
No entanto, quando chegou à linha 20, atingiu o primeiro breakpoint e parou a execução do programa (não parou na linha 7, porque esta está dentro de uma função, e esta ainda não foi executada).
Continuando:
(Pdb) continue
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(7)soma_todos_numeros()
-> soma = 0
(Pdb)
Podem ver que parou na linha 7, dentro da função (usem o
list para confirmarem se quiserem).
Se voltarem a usar
continue, ele vai correr o programa até ao fim vistos ele não encontrar mais nenhum breakpoint (se por acaso esta função fosse chamada mais à frente no programa, o pdb voltaria a parar na linha 7).
E isto acaba a introdução de como usar o pdb.
Agora é só ver como se pode chamar o pdb dentro de um programa de Python.
Nesta introdução só vou falar do método
set_trace() e do
run().
O set_trace(), faz com que o programa pare e entre no pdb sempre que chega a essa linha.
O run() avalia uma string como se fosse um comando de python, e corre-o no pdb.
Vamos descomentar a linha 6 do programa (a que diz
pdb.set_trace()) e a linha 3 (
import pdb).
rolando@main-computer:~/Programacao/Python/meus_scripts/tutorial_debugging$ python exemplo2.py
Bem-vindo ao programa que soma todos os numeros!
Quer somar todos os numeros de 0 ate?
Numero: 10
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(7)soma_todos_numeros()
-> soma = 0
(Pdb)
E estão de volta ao pdb, na linha a seguir à linha do set_trace().
Para verem o run(), voltem a comentar a linha 6, comentando também a linha 20, e descomentando a linha 21.
rolando@main-computer:~/Programacao/Python/meus_scripts/tutorial_debugging$ python exemplo2.py
Bem-vindo ao programa que soma todos os numeros!
Quer somar todos os numeros de 0 ate?
Numero: 10
> <string>(1)<module>()
(Pdb) step
--Call--
> /home/rolando/Programacao/Python/meus_scripts/tutorial_debugging/exemplo2.py(5)soma_todos_numeros()
-> def soma_todos_numeros(numero):
(Pdb)
Usem o
step para entrarem na função.
(Lembrem-se, se quiserem continuar com a execução do programa, têm de usar o comando
continue).
E é tudo por hoje. Sei que parece muito, mas com a prática vão ver que é fácil.
Ainda à algumas coisas que não falei, como temporary breakpoints (o continue só pára lá uma vez), mas já têm muito para trabalhar.
Só mais uma coisa.
Se acharem que não estão com paciência para aprender estes comandos todos, podem sempre tentar o modo Debug do IDLE (está lá no ménu Debug).
Se não quiserem usar o pdb, lembrem-se que existem outros (talvez melhores e com mais opções, e mais parecidos com o Gdb), como o
Pydb, que pode ser usado num ambiente mais gráfico com o programa
DDD (este tem também a vantagem de suportar outros debuggers como o Gdb).