处理Python pdb不稳定性与输出的最佳方法是什么?

6 投票
3 回答
2004 浏览
提问于 2025-04-15 17:21

如果我有一个程序,它的 stdout 被重定向了,那么我在使用调试工具 pdb 时,所有的提示信息都会发送到这个重定向的地方,因为这个库是设计成写入 stdout 的。

这个问题有时候很微妙,让我误以为程序卡住了,其实它只是在等待输入。

大家是怎么解决这个问题的呢?(不幸的是,像 winpdb 这样的其他调试工具也不能用)。

3 个回答

2

如果你是在代码中使用pdb(Python的调试工具),你可以把自己的输出流传给它的构造函数。比如说,sys.__stdout__可能是个不错的选择。

如果你是从命令行调用pdb,你可以把pdb.py里的main()函数复制到你自己创建的sane_pdb.py文件里。然后把Pdb()的初始化改成:

pdb = Pdb(stdout=sys.__stdout__)

这样你就可以运行sane_pdb.py,而不是pdb.py了。虽然为了改一行代码你需要复制40行到自己的文件里,这样做并不是特别方便,但这也是一种解决办法。

5

这个回答是为了补充Ned的内容,目的是为了以一种不需要复制40行代码就能修改其中一行的方式来包装pdb.py的main()函数:

# sane_pdb.py: launch Pdb with stdout on original
import sys, pdb
def fixed_pdb(Pdb=pdb.Pdb):
    '''make Pdb() tied to original stdout'''
    return Pdb(stdout=sys.__stdout__)

if __name__ == '__main__':
    pdb.Pdb = fixed_pdb
    pdb.main()

我不知道这个方法是否真的能解决提问者的问题,但它确实实现了Ned所描述的功能……

4

这里的问题是,PDB使用了Cmd类,而默认情况下:

use_rawinput = 1

这意味着Cmd会默认使用raw_input()方法来从控制台读取输入,而不是sys.stdout.readline()。这样做的原因是raw_input()支持历史记录(前提是加载了readline模块)和其他一些有用的功能。唯一的问题是,raw_input()不支持重定向,所以如果你有一个脚本:

#!/usr/bin/python
name=raw_input("Enter your name: ")

并且运行它

> python test.py
Enter your name: Alex

但是,如果你用输出重定向来运行它,它就会卡住

> python test.py | tee log

这正是PDB使用的方式,也是它卡住的原因。如我所提到的,sys.stdin.readline()支持重定向,如果你用readline()重写上面的脚本,它应该就能正常工作。

回到最初的问题,你需要做的就是告诉Cmd不要使用raw_input()

Cmd.use_rawinput = 0

或者

pdb = pdb.Pdb()
pdb.use_rawinput=0
pdb.set_trace()

撰写回答