首页 > Python基础教程 >
-
常用的 Python 调试工具,Python开发必读
以下是我做调试或分析时用过的工具的一个概览。如果你知道有更好的工具,请在评论中留言,可以不用很完整的介绍。
日志
没错,就是日志。再多强调在你的应用里保留足量的日志的重要性也不为过。你应当对重要的内容打日志。如果你的日志打的足够好的话,单看日志你就能发现问题所在。那样可以节省你大量的时间。
如果一直以来你都在代码里乱用 print 语句,马上停下来。换用logging.debug。以后你还可以继续复用,或是全部停用等等。
跟踪
有时更好的办法是看执行了哪些语句。你可以使用一些IDE的调试器的单步执行,但你需要明确知道你在找那些语句,否则整个过程会进行地非常缓慢。
标准库里面的trace模块,可以打印运行时包含在其中的模块里所有执行到的语句。(就像制作一份项目报告)
1
|
python - mtrace –trace script.py |
这会产生大量输出(执行到的每一行都会被打印出来,你可能想要用grep过滤那些你感兴趣的模块).
比如:
1
|
python - mtrace –trace script.py | egrep '^(mod1.py|mod2.py)' |
调试器
以下是如今应该人尽皆知的一个基础介绍:
1
2
|
import pdb pdb.set_trace() # 开启pdb提示 |
或者
1
2
3
4
5
6
7
|
try : (一段抛出异常的代码) except : import pdb pdb.pm() # 或者 pdb.post_mortem() 或者(输入 c 开始执行脚本) |
python -mpdb script.py
在输入-计算-输出循环(注:REPL,READ-EVAL-PRINT-LOOP的缩写)环境下,可以有如下操作:
c or continue
q or quit
l or list, 显示当前步帧的源码
w or where,回溯调用过程
d or down, 后退一步帧(注:相当于回滚)
u or up, 前进一步帧
(回车), 重复上一条指令
其余的几乎全部指令(还有很少的其他一些命令除外),在当前步帧上当作python代码进行解析。
如果你觉得挑战性还不够的话,可以试下smiley,-它可以给你展示那些变量而且你能使用它来远程追踪程序。
更好的调试器
pdb的直接替代者:
ipdb(easy_install ipdb) – 类似ipython(有自动完成,显示颜色等)
pudb(easy_install pudb) – 基于curses(类似图形界面接口),特别适合浏览源代码
远程调试器
安装方式:
sudo apt-get install winpdb
用下面的方式取代以前的pdb.set_trace():
1
2
|
import rpdb2 rpdb2.start_embedded_debugger( "secretpassword" ) |
现在运行winpdb,文件-关联
不喜欢Winpdb?也可以直接包装PDB在TCP之上运行!
这样做:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
import loggging class Rdb(pdb.Pdb): """ This will run pdb as a ephemeral telnet service. Once you connect no one else can connect. On construction this object will block execution till a client has connected. Based on https://github.com/tamentis/rpdb I think ... To use this:: Rdb(4444).set_trace() Then run: telnet 127.0.0.1 4444 """ def __init__( self , port = 0 ): self .old_stdout = sys.stdout self .old_stdin = sys.stdin self .listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self .listen_socket.bind(( '0.0.0.0' , port)) if not port: logging.critical( "PDB remote session open on: %s" , self .listen_socket.getsockname()) print >> sys.__stderr__, "PDB remote session open on:" , self .listen_socket.getsockname() sys.stderr.flush() self .listen_socket.listen( 1 ) self .connected_socket, address = self .listen_socket.accept() self .handle = self .connected_socket.makefile( 'rw' ) pdb.Pdb.__init__( self , completekey = 'tab' , stdin = self .handle, stdout = self .handle) sys.stdout = sys.stdin = self .handle def do_continue( self , arg): sys.stdout = self .old_stdout sys.stdin = self .old_stdin self .handle.close() self .connected_socket.close() self .listen_socket.close() self .set_continue() return 1 do_c = do_cont = do_continue def set_trace(): """ Opens a remote PDB on first available port. """ rdb = Rdb() rdb.set_trace() |