Python3之调试
程序能一次写完并正常运行的概率很小,基本不超过1%。总会有各种各样的bug需要修正。有的bug很简单,看看错误信息就知道,有的bug很复杂,我们需要知道出错时,哪些变量的值是正确的,哪些变量的值是错误的,因此,需要一整套调试程序的手段来修复bug。
第一种方法简单直接粗暴有效,就是用print()
把可能有问题的变量打印出来看看:
err3.py
1 2 3 4 5 6 7 | def foo(s): n = int (s) print ( '>>>n=%d' % n) return 10 / n def main(): foo( '0' ) main() |
运行结果,在输出中可以查找到打印的变量值
1 2 3 4 5 6 7 8 9 | >>>n = 0 Traceback (most recent call last): File "err3.py" , line 7 , in <module> main() File "err3.py" , line 6 , in main foo( '0' ) File "err3.py" , line 4 , in foo return 10 / n ZeroDivisionError: division by zero |
用print()最大的坏处是程序调试完毕需要删除,程序到处都是print(),运行结果也包含大量垃圾信息。所以,我们又有第二种方法
do_assert.py
断言
1 2 3 4 5 6 7 8 9 | def foo(s): n = int (s) assert n ! = 0 , 'n is zero!' return 10 / n def main(): foo( '0' ) main() |
assert的意思是,表达式n!=0应该是True,否则,根据程序运行的逻辑,后面的代码肯定会出错
如果断言失败,assert语句本身就会抛出AssertionError
运行结果
1 2 3 4 5 6 7 8 | Traceback (most recent call last): File "do_assert.py" , line 12 , in <module> main() File "do_assert.py" , line 10 , in main foo( '0' ) File "do_assert.py" , line 6 , in foo assert n ! = 0 , 'n is zero!' AssertionError: n is zero! |
程序中如果到处充斥着assert
,和print()
相比也好不到哪去。不过,启动Python解释器时可以用-O
参数来关闭assert
:
1 | python3 - O do_assert.py |
运行结果
1 2 3 4 5 6 7 8 | Traceback (most recent call last): File "do_assert.py" , line 12 , in <module> main() File "do_assert.py" , line 10 , in main foo( '0' ) File "do_assert.py" , line 7 , in foo return 10 / n ZeroDivisionError: division by zero |
关闭后,可以把所有的assert语句当成pass来看
logging
把print()替换成logging是第3种方式,和assert比,logging不会抛出错误,而且可以输出到文件
err4.py
1 2 3 4 5 6 | import logging #logging.basicConfig(level=logging.INFO) s = '0' n = int (s) logging.info( 'n=%d' % n) print ( 10 / n) |
logging.info()就可以输出一段文本。运行,发现除了ZeroDivisionError,没有任何信息
1 2 3 4 | Traceback (most recent call last): File "err4.py" , line 6 , in <module> print ( 10 / n) ZeroDivisionError: division by zero |
修改增加配置
1 2 3 4 5 6 | import logging logging.basicConfig(level = logging.INFO) s = '0' n = int (s) logging.info( 'n=%d' % n) print ( 10 / n) |
运行结果
1 2 3 4 5 | INFO:root:n = 0 Traceback (most recent call last): File "err4.py" , line 6 , in <module> print ( 10 / n) ZeroDivisionError: division by zero |
这就是logging
的好处,它允许你指定记录信息的级别,有debug
,info
,warning
,error
等几个级别,当我们指定level=INFO
时,logging.debug
就不起作用了。同理,指定level=WARNING
后,debug
和info
就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。
logging
的另一个好处是通过简单的配置,一条语句可以同时输出到不同的地方,比如console和文件。
pdb
第4种方式是启动python的调速器pdb,让程序以单步方式运行,可以随时查看运行状态
err5.py
1 2 3 4 | #err5.py s = '0' n = int (s) print ( 10 / n) |
启动
1 | python3 - m pdb err5.py |
以参数-m pdb启动后,pdb定位到下一步要执行的代码->s='0'
1 2 | > / nas / scripts / python / learn - python3 / samples / debug / err5.py( 2 )<module>() - > s = '0' |
可以输入字母l来查看代码
1 2 3 4 5 | (Pdb) l 1 #err5.py 2 - > s = '0' 3 n = int (s) 4 print ( 10 / n) |
输入n可以单步执行代码
1 2 3 | (Pdb) n > / nas / scripts / python / learn - python3 / samples / debug / err5.py( 3 )<module>() - > n = int (s) |
1 2 | > / nas / scripts / python / learn - python3 / samples / debug / err5.py( 4 )<module>() - > print ( 10 / n) |
1 2 3 4 | (Pdb) n ZeroDivisionError: division by zero > / nas / scripts / python / learn - python3 / samples / debug / err5.py( 4 )<module>() - > print ( 10 / n) |
任何时候都可以输入p 加变量名查看变量
1 2 | (Pdb) p s '0' |
输入q结束调试
这种通过pdb在命令行调试的方法理论上是万能的,但实在是太麻烦了,如果有一千行代码,要运行到第999行得敲多少命令啊。还好,我们还有另一种调试方法。
pdb.set_trace()
这个方法也是用pdb,但是不需要单步执行,我们只需要import pdb
,然后,在可能出错的地方放一个pdb.set_trace()
,就可以设置一个断点:
err6.py
1 2 3 4 5 6 7 | #err6.py import pdb s = '0' n = int (s) #运行到这来会自动暂停 pdb.set_trace() print ( 10 / n) |
运行代码,程序会自动在pdb.set_trace()
暂停并进入pdb调试环境,可以用命令p
查看变量,或者用命令c
继续运行:
1 2 3 4 5 6 7 8 9 10 | (base) [root@prd - zabbix debug] # python3 err6.py > / nas / scripts / python / learn - python3 / samples / debug / err6.py( 7 )<module>() - > print ( 10 / n) (Pdb) p n 0 (Pdb) c Traceback (most recent call last): File "err6.py" , line 7 , in <module> print ( 10 / n) ZeroDivisionError: division by zero |
IDE
如果要比较爽地设置断点、单步执行,就需要一个支持调试功能的IDE。目前比较好的Python IDE有:
Visual Studio Code:https://code.visualstudio.com/,需要安装Python插件。
PyCharm:http://www.jetbrains.com/pycharm/
另外,Eclipse加上pydev插件也可以调试Python程序。
小结
写程序最痛苦的事情莫过于调试,程序往往会以你意想不到的流程来运行,你期待执行的语句其实根本没有执行,这时候,就需要调试了。
虽然用IDE调试起来比较方便,但是最后你会发现,logging才是终极武器。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!