错误时自动启动python调试器


216

这是我很长时间以来一直想知道的一个问题,但是我从未找到合适的解决方案。如果我运行了一个脚本并且碰到了一个类似IndexError的错误,python将打印错误的行,位置和快速描述,然后退出。遇到错误是否可以自动启动pdb?我不反对在文件顶部添加多余的import语句,也不反对添加几行代码。


12
您是否考虑过更改接受的答案?
Joost

Answers:


127

您可以使用traceback.print_exc打印异常跟踪。然后使用sys.exc_info提取回溯,最后使用该回溯调用pdb.post_mortem

import pdb, traceback, sys

def bombs():
    a = []
    print a[0]

if __name__ == '__main__':
    try:
        bombs()
    except:
        extype, value, tb = sys.exc_info()
        traceback.print_exc()
        pdb.post_mortem(tb)

如果要使用产生异常的框架的局部语言使用code.interact启动交互式命令行,可以执行

import traceback, sys, code

def bombs():
    a = []
    print a[0]

if __name__ == '__main__':
    try:
        bombs()
    except:
        type, value, tb = sys.exc_info()
        traceback.print_exc()
        last_frame = lambda tb=tb: last_frame(tb.tb_next) if tb.tb_next else tb
        frame = last_frame().tb_frame
        ns = dict(frame.f_globals)
        ns.update(frame.f_locals)
        code.interact(local=ns)

将第一溶液进一步在所讨论的蟒食谱
dirkjot

3
既然后者似乎在前者的基础上扩大code了,为什么有人会喜欢pdb呢?
K3 --- rnc 2014年

我有同样的问题吗?你为什么会喜欢code
ARH 2015年

2
然后使用sys.exc_info提取回溯,最后pdb.post_mortem使用该回溯调用。您无需将traceback对象传递给pdb.post_mortem。来自docs如果未提供回溯,它将使用当前正在处理的异常之一(如果要使用默认值,则必须处理异常)。
Piotr Dobrogost 2015年

2
@PiotrDobrogost好点。我认为知道可以传递tb对象会更有用,因为它可以更好地演示API。很高兴知道这两种选择都存在。
davidA

453
python -m pdb -c continue myscript.py

如果不提供-c continue标志,则在执行开始时需要输入“ c”(代表“继续”)。然后它将运行到错误点,并在那里给您控制。如eqzx所述,此标志是python 3.2中的新增功能,因此,对于早期的Python版本,请输入'c'(请参阅https://docs.python.org/3/library/pdb.html)。


5
感谢您提到“ 输入'c' ”-我通常用来输入'r'(代表“运行”),我习惯于从它开始gdb;当您在中输入'r'时pdb,程序确实可以运行,但是不会因错误而停止(也不生成回溯);让我感到困惑,直到我读到这篇文章。干杯!
sdaau

3
Vineet,它将启动调试器,因此输入“ cont”,它将一直运行直到遇到错误。从那里您可以像在其他任何pdb会话中一样检查变量等。
凯瑟琳·德夫林

40
请操作,接受此作为答案。这是最有用的方法,我浪费了5分钟阅读其他文章,直到我找到了这个……这应该是第一个!
jhegedus

4
这也适用于ipdb; 当然可以在脚本之后添加参数!
tutuDajuju 2015年

20
这不适用于Python 2.7。docs.python.org/3/library/pdb.html:“3.2版中的新增功能:pdb.py现在接受执行命令的-c选项”
eqzx

68

使用以下模块:

import sys

def info(type, value, tb):
    if hasattr(sys, 'ps1') or not sys.stderr.isatty():
    # we are in interactive mode or we don't have a tty-like
    # device, so we call the default hook
        sys.__excepthook__(type, value, tb)
    else:
        import traceback, pdb
        # we are NOT in interactive mode, print the exception...
        traceback.print_exception(type, value, tb)
        print
        # ...then start the debugger in post-mortem mode.
        # pdb.pm() # deprecated
        pdb.post_mortem(tb) # more "modern"

sys.excepthook = info

命名debug(或您喜欢的任何名称)并将其放在python路径中的某个位置。

现在,在脚本的开头,只需添加一个即可import debug


2
这应该是公认的答案-不需要修改现有代码,也不需要将所有内容包装在try-catchIMO中。
cyphar

我喜欢这个答案相当频繁,但更喜欢pudbpdb。继续回到复制粘贴,这肯定说明了我一生中缺乏秩序。
稳定狗

47

Ipython有一个用于切换此行为的命令:%pdb。它的功能完全符合您的描述,甚至可能更多(通过语法高亮和代码完成为您提供更多有用的回溯信息)。绝对值得一试!


3
这是对此的唯一合理答案。
迈克尔


4
请注意,正如在@matthiash链接的文档中也指出的那样,它%debug允许您遇到错误打开调试器。我经常喜欢这个%pdb。(权衡的只是输入q你不想调试误差与输入每一次%debug当你每次要调试的错误。)
布拉汉姆斯奈德

1
另请注意,设置c.InteractiveShell.pdb = True在一个人的ipython_config.py轮番%pdb自动为每个会话。
布拉汉姆·斯奈德

33

这不是调试器,但可能同样有用(?)

我知道我听到Guido在某处的演讲中提到了这一点。

我刚刚检查了python-?,如果您使用-i命令,则可以在脚本停止的地方进行交互。

因此,鉴于此脚本:

testlist = [1,2,3,4,5, 0]

prev_i = None
for i in testlist:
    if not prev_i:
        prev_i = i
    else:
        result = prev_i/i

您可以获得此输出!

PS D:\> python -i debugtest.py
Traceback (most recent call last):
  File "debugtest.py", line 10, in <module>
    result = prev_i/i
ZeroDivisionError: integer division or modulo by zero
>>>
>>>
>>> prev_i
1
>>> i
0
>>>

老实说,我没有使用过,但是应该使用,这似乎很有用。


重量

8
几乎没有用处,而是进入了全球范围。不管发生什么功能崩溃都无法翻阅。
pixelpax

21

IPython在命令行上使这一过程变得简单:

python myscript.py arg1 arg2

可以重写为

ipython --pdb myscript.py -- arg1 arg2

或者,类似地,如果调用模块:

python -m mymodule arg1 arg2

可以重写为

ipython --pdb -m mymodule -- arg1 arg2

请注意,--以阻止IPython读取脚本的自变量。

这也具有调用增强的IPython调试器(ipdb)而不是pdb的优势。


9

如果您使用ipython,请在启动后输入%pdb

In [1]: %pdb
Automatic pdb calling has been turned ON

例如
Jupyter

6

如果您使用的是IPython环境,则可以只使用%debug,外壳程序会将您带回到ipdb环境进行检查等问题。如上所述,另一种选择是使用iPython魔术%pdb,它可以有效地相同。


请注意,如果错误发生在模块功能中,则可以使用updown命令浏览框架,返回到产生错误的代码行。
让·保罗


3

要使其运行而不必在开始使用时键入c:

python -m pdb -c c <script name>

Pdb有其自己的命令行参数:-cc将在执行开始时执行c(ontinue)命令,并且程序将不间断运行直至出现错误。


3

python2.7中的python -m pdb script.py按继续启动,它将运行到错误并在此处中断以进行调试。


1

如果您正在运行模块:

python -m mymodule

现在,您想pdb在发生异常时输入信息,请执行以下操作:

PYTHONPATH="." python -m pdb -c c mymodule/__main__.py

(或扩展您的PYTHONPATH)。的PYTHONPATH需要,使模块在路径中发现,因为你运行的是pdb现在的模块。


0

在层次结构中最顶层异常类的构造函数中放置一个断点,大多数情况下,您将看到引发错误的位置。

放置断点意味着您想要表达的含义:您可以使用IDE或pdb.set_trace,或任何其他方式

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.