Criando um programa em python com debug - helio.loureiro.eng.br
Categoria: Python	Publicado: Domingo, 28 Fevereiro 2016	Escrito por Helio Loureiro	Imprimir
Vou descrever aqui mais uma dica de uso que um processo ou ferramenta. Como faz vários anos que programo em python, em certo ponto achei razoável adicionar uma variável e parâmetro pra debug. Então todos meu programas em python em geral tem uma estrutura mais ou menos assim:
print "DEBUG: %s" % msg
o = MinhaClasse()
o.main()
Então o que faço em geral é ter uma função debug(), mesmo que use classe e orientação à objetos, pra facilitar a chamada. Porque eu uso a função? Se eu usar como método dentro da classe, tem de chamar toda vez como self.debug(). Como não vejo muita vantagem nisso, prefiro definir sempre como função no topo do código.
Mas esse é um exemplo pra mostrar o princípio. O que uso é um pouco mais elaborado que isso. Vamos melhorar esse código pra entender melhor criando alguns métodos como __init__() e main().
debug("Construtor da classe")
def fazalgo(self):
debug("Fazendo algo")
debug("Chamando main")
self.fazalgo()
opts, args = getopt.getopt(sys.argv[1:], "d")
debug("DEBUG ENABLED")
Primeiramente eu adicione algum tipo de verificação de opção. Pode ser com getopt como argparse. Como é uma opção simples, pra verificar o parâmetro "-d", de debug ativo, usei getopt. Em seguida usei uma variável global DEBUG, que fica como padrão em False, ou seja, desligado.
Quando faço a chamada na parte de baixo, onde __name__ é '__main__', verifico a opção via flag ou via variável de shell. Isso quer dizer que se eu usar o script de 2 formas, terei debug ativado:
> ./meuscript.py -d
> env DEBUG=1 ./meuscript.py
a segunda forma ajuda no caso de ter um sistema mais complexo e um shell script chamar seu programa. Daí se vários scripts verificarem as variáveis de shell pra buscar por DEBUG (ou $DEBUG), fica fácil ativar/desativar.
E assim até hoje eu debugo meus programas. Claro que fiz alguns aperfeiçoamentos como uma função que imprime o nome do método que está rodando.
def __funcname__(depth=0):
To print function names like __func__ in C.
return "__function__: " + sys._getframe(depth + 1).f_code.co_name + "()"
Assim, dentro de um método, posso usar debug da seguinte forma:
debug(__funcname__)
E isso ajuda ao imprimir o nome da função corrente, da mesma forma que se usa a macro__FUNCTION__ em C. Essa dica eu achei recentement no StackOverflow:
http://stackoverflow.com/questions/5067604/determine-function-name-from-within-that-function-without-using-traceback
E por último, e acabei com o tempo refinando meu debug(). Ao invés de de somente aceitar string, eu fiz um seletor de tipo pra imprimir qualquer variável, inclusive dicionários no formato json pra ficar mais fácil ler.
""" Debug helper """
if type(msg) == type("abc"):
# it is ok
elif type(msg) == type({}):
msg = "%s" % json.dumps(msg, indent=4)
elif type(msg) == type([]):
msg = "[ %s ]" % ", ".join(msg)
msg = "DEBUG(%s): %s" % (__file__, msg)
syslog.syslog(syslog.LOG_DEBUG, msg)
self.nome = "Helio"
self.sobrenome = "Loureiro"
debug("Nome: %s" % self.nome)
debug("Sobrenome: %s" % self.sobrenome)
self.dados = {}
for k, v in self.dados.items():
debug("%s => %s" % (k, v) )
self.dados = { "Nome" : self.nome,
"Sobrenome" : self.sobrenome }
debug(self.dados)
Como escrevi anteriormente, não é um padrão fazer isso. Existem módulos que ajudam a debuggar de forma até mais profunda. Eu gosto de escrever minhas mensagens de debug pra filtrar melhor as mensagens e poder ver o que realmente importa. Então fica aqui a dica.