程序一次完成并正常运行的概率很小,基本不超过1%。总有各种各样的错误需要纠正。有些错误很简单。从错误的信息可以看出,有些错误非常复杂。当我们犯错误时,我们需要知道哪些变量值是正确的,哪些变量值是错误的。因此,我们需要一套完整的调试程序来修复错误。
第一种方法简单、直接、粗糙、有效,即用print打印可能出现问题的变量:
#err.py deffoo(s): n=int(s) print'>>>n=%d'%n return10/n defmain(): foo('0') main()
执行后,在输出中找到打印的变量值:
$pythonerr.py >>>n=0 Traceback(mostrecentcalllast): ... ZeroDivisionError:integerpisionormodulobyzero
使用print的缺点是将来必须删除它。想想程序中到处都是print,操作结果也会包含大量的垃圾信息。因此,我们有第二种方法。
断言
任何使用print辅助查看的地方都可以使用断言(assert)来替代:
#err.py deffoo(s): n=int(s) assertn!=0,'niszero!' return10/n defmain(): foo('0')
assert的意思是表达n != 0应该是True,否则后面的代码会出错。
如果断言失败,assert语句本身就会抛出assertionerororor:
$pythonerr.py Traceback(mostrecentcalllast): ... AssertionError:niszero!
如果程序中到处都是assert,那就比print好不了多少。但是,在启动Python解释器时,可以使用-o参数关闭assert:
$python-Oerr.py Traceback(mostrecentcalllast): ... ZeroDivisionError:integerpisionormodulobyzero
关闭后,您可以将所有assert语句视为pass。
logging
用loging代替print是第三种方式,与assert相比,loging不会出错,而且可以输出到文件中:
#err.py importlogging s='0' n=int(s) logging.info('n=%d'%n) print10/n
logging.info()可以输出一段文本。运行时,发现除Zerodivisioneror外,没有任何信息。怎么回事?
别担心,import 在loging之后,添加一行配置再次尝试:
importlogging logging.basicConfig(level=logging.INFO)
看输出:
$pythonerr.py INFO:root:n=0 Traceback(mostrecentcalllast): File"err.py",line8,in<module> print10/n ZeroDivisionError:integerpisionormodulobyzero
这就是loging的好处,它允许你指定记录信息的级别,有debug,info,warning,当我们指定level=INFO时,error等几个级别,logging.debug不起作用。同样,在指定level=WARNING后,debug和info也不起作用。这样,您就可以在不删除的情况下放心输出不同级别的信息,最终统一控制输出级别的信息。
logging的另一个优点是,一个句子可以通过简单的配置同时输出到不同的位置,例如console和文件。
pdb
第四种方法是启动Python调试器pdb,使程序单步运行,随时检查运行状态。我们首先准备程序:
#err.py s='0' n=int(s) print10/n
然后启动:
$python-mpdberr.py >/Users/michael/Github/sicp/err.py(2)<module>() ->s='0'
以参数-m pdb启动后,pdb定位到下一步要执行的代码-> s = '0'。输入命令l查看代码:
(Pdb)l 1#err.py 2->s='0' 3n=int(s) 4print10/n [EOF]
输入命令n可以单步执行代码:
(Pdb)n >/Users/michael/Github/sicp/err.py(3)<module>() ->n=int(s) (Pdb)n >/Users/michael/Github/sicp/err.py(4)<module>() ->print10/n
任何时候都可以输入命令p 变量名检查变量:
(Pdb)ps '0' (Pdb)pn 0
输入命令q结束调试,退出程序:
(Pdb)n ZeroDivisionError:'integerpisionormodulobyzero' >/Users/michael/Github/sicp/err.py(4)<module>() ->print10/n (Pdb)q
理论上,这种通过pdb调试命令行的方法是万能的,但太麻烦了。如果有1000行代码,需要敲多少命令才能运行到第99行。幸运的是,我们还有另一种调试方法。
pdb.set_trace()
这种方法也使用pdb,但不需要单步执行。我们只需要import pdb,然后,在可能出错的地方放一个pdb.set_trace(),可以设置断点:
#err.py importpdb s='0' n=int(s) pdb.set_trace()#运行到这里会自动暂停 print10/n
在pdbb中自动操作代码.set_trace()暂停并进入pdb调试环境,可以用命令p查看变量,也可以用命令c继续运行:
$pythonerr.py >/Users/michael/Github/sicp/err.py(7)<module>() ->print10/n (Pdb)pn 0 (Pdb)c Traceback(mostrecentcalllast): File"err.py",line7,in<module> print10/n ZeroDivisionError:integerpisionormodulobyzero
这种方法比直接启动pdb单步调试要有效得多,但也不高。
IDE
如果要设置断点,单步执行,需要IDE支持调试功能。目前比较好的Python IDE有PyCharm:
http://www.jetbrains.com/pycharm/
此外,Eclipse和pydev插件也可以调试Python程序。
小结
写程序最痛苦的事情是调试。程序通常以你意想不到的过程运行。事实上,你期望执行的陈述根本没有执行。此时,有必要进行调试。
虽然用IDE调试更方便,但最终你会发现loging是终极武器。
python培训视频众多,全部在python学习网,欢迎在线学习!