一直学一直嗨,一直嗨一直学

调试你的Python代码

调试你的Python代码

译自:http://howchoo.com/g/zgi2y2iwyze/debugging-your-python-code 
作者:Ashley 
  当你不得不更新别人的代码时,你有多少次陷入这样一种境地?如果你是一个开发团队的一员,那我猜一定多于你愿意的次数。结果我们发现Python(和其他语言一样)提供了在这种情况下便利的debug特性。愿这份快速指南能使你的生活轻松些。

1一段糟糕的代码

  出于本教程段目的让我们假设如下一段简单段程序。这段程序获取两个命令行参数以及加减操作。(让我们假设用户输入的参数无误,因此无需处理异常)

importsysdefadd(num1=0,num2=0):returnint(num1)+int(num2)defsub(num1=0,num2=0):returnint(num1)-int(num2)defmain():#Assumingourinputsarevalidnumbersprintsys.argvaddition=add(sys.argv[1],sys.argv[2])printadditionsubtraction=sub(sys.argv[1],sys.argv[2])printsubtractionif__name__=='__main__':main()

2加入pdb

Python自带了名为pdb的,基于交互的源码debug模块。
你需要已如下方式启用该模块。 

importpdbpdb.set_trace() 加入断点(breakpoints)的示例程序:

importpdbimportsysdefadd(num1=0,num2=0):returnint(num1)+int(num2)defsub(num1=0,num2=0):returnint(num1)-int(num2)defmain():#Assumingourinputsarevalidnumbersprintsys.argvpdb.set_trace()#<--Breakpointaddedhereaddition=add(sys.argv[1],sys.argv[2])printadditionsubtraction=sub(sys.argv[1],sys.argv[2])printsubtractionif__name__=='__main__':main()

#/Users/someuser/debugger.py(15)main()->addition=add(sys.argv[1],sys.argv[2])(Pdb)我们会看到下次被执行的将是第15行。
程序在执行第15行前暂停了。
我们在这里有一些选择。。。让我们在接下来的步骤中展示其中一部分。

4下一行->n
在debugger提示符处按”n”会到下一行。

>/Users/someuser/debugger.py(14)main()->addition=add(sys.argv[1],sys.argv[2])(Pdb)n>/Users/someuser/debugger.py(15)main()->printaddition 这会执行当前行并准备好执行下一行。
我们虽然能够通过使用”n”来一行行执行程序,但这样不是太有用。
你可能已经注意到了pdb实际上并没有进入add函数中。让我们在看看debugger的其他选项,使排错变得更有趣。 

 注意:
 另一个酷酷的特性是按回车键会执行你之前执行过的命令(本例中为”n”)。

5打印->p
让我们再次开始debug吧!(既然我们没有任何程序会执行完。你可以敲击”c”使pdb跳至最后或者下一个断点(breakpoint) 

['debugger.py','1','2']>/Users/someuser/debugger.py(14)main()->addition=add(sys.argv[1],sys.argv[2])(Pdb)现在如果我们想知道sys.argv包含了哪些参数,我们可以这么干:

->addition=add(sys.argv[1],sys.argv[2])(Pdb)psys.argv['debugger.py','1','2'](Pdb)psys.argv[1]'1'(Pdb) 这在检测变量实际存储的值时非常有用。
现在让我们进入add函数内部

6进入函数->s
我们可以通过使用”s”来进入我们的addition函数。

(Pdb)s--Call-->/Users/someuser/debugger.py(4)add()->defadd(num1=0,num2=0):(Pdb)n>/Users/someuser/debugger.py(5)add()->returnint(num1)+int(num2)(Pdb) 这使我们来到了add函数的内部,现在我们能够在其中使用”n,p”以及其他操作了。
这时敲击”r”会跳转至所进入函数的返回语句处。(译注:再次敲击时会跳转至函数调用处)
这在你想快速跳转至方法结尾时很有用。

7动态添加断点(breakpoint)->b
我们在运行程序前通过pdb.set_trace()设置了断点(breakpoint)
通常在debugger开始后,我们会想在一些特定的位置设置断点(breakpoint)
好基友“b”登场。
让我们再次执行我们的程序

['debugger.py','1','2']>/Users/someuser/debugger.py(15)main()->addition=add(sys.argv[1],sys.argv[2])(Pdb)现在我在第18行设置一个断点(breakpoint)。

->addition=add(sys.argv[1],sys.argv[2])(Pdb)b18Breakpoint1at/Users/someuser/debugger.py:18(Pdb)cWeareinadd--3>/Users/someuser/debugger.py(18)main()->printsubtraction(Pdb)psubtraction-1(Pdb)如我们所见,pdb直接跳至第18行并等待进一步指令。
pdb也会给断点赋一个数字(本例中为数字1)。我们能够使用(原文为”user”疑似笔误)
enable/disable断点(breakpoint)数字再进一步执行中启用或关闭相对应的断点(breakpoint)。

8列表->l
有时在debug的过程中,你会迷失于代码中。此时,你可以使用”l”来输出一个格式良好的摘要来告知你你身在何处。#斟酌

['debugger.py','1','2']>/Users/someuser/debugger.py(15)main()->addition=add(sys.argv[1],sys.argv[2])(Pdb)l1011defmain():12#Assumingourinputsarevalidnumbers13printsys.argv14pdb.set_trace()#<--Breakpointaddedhere15->addition=add(sys.argv[1],sys.argv[2])16printaddition17subtraction=sub(sys.argv[1],sys.argv[2])18printsubtraction

9给变量动态赋值

在debug时,能给变量赋值也有助于排错。
假设:

['debugger.py','1','2']>/Users/someuser/debugger.py(15)main()->addition=add(sys.argv[1],sys.argv[2])(Pdb)nWeareinadd-->/Users/someuser/debugger.py(16)main()->printaddition(Pdb)paddition3#<---additionhereis3(Pdb)addition='thisisnowstring'#<---Wechangedthevalueofadditon(Pdb)nthisisnowstring#<---Nowwhenweprintitweactuallygetsitasastring.thatwejustsetabove.>/Users/someuser/debugger.py(17)main()->subtraction=sub(sys.argv[1],sys.argv[2])注意:
如果你想给像”n”这样的变量赋值(即同时也是pdb命令),你需要这样做:

(Pdb)!n=5(Pdb)pn5

10退出->q

最后你可以通过”q”,在任何时刻退出。程序执行会被终止。

11扩展阅读

本文仅仅触及pdb的表面。还有更多的文档在向你招手!
那些使用ipython的能够在ipdb中找到更好的debugger:tab补全,语法高亮以及其他酷酷的特性。
如果你有其他使用pdb的有趣方法请在下面评论
排错愉快!

Tags:,