错误时自动启动python调试器

问题:错误时自动启动python调试器

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

This is a question I have wondered about for quite some time, yet I have never found a suitable solution. If I run a script and I come across, let’s say an IndexError, python prints the line, location and quick description of the error and exits. Is it possible to automatically start pdb when an error is encountered? I am not against having an extra import statement at the top of the file, nor a few extra lines of code.


回答 0

您可以使用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)

You can use traceback.print_exc to print the exceptions traceback. Then use sys.exc_info to extract the traceback and finally call pdb.post_mortem with that traceback

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)

If you want to start an interactive command line with code.interact using the locals of the frame where the exception originated you can do

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)

回答 1

python -m pdb -c continue myscript.py

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

python -m pdb -c continue myscript.py

If you don’t provide the -c continue flag then you’ll need to enter ‘c’ (for Continue) when execution begins. Then it will run to the error point and give you control there. As mentioned by eqzx, this flag is a new addition in python 3.2 so entering ‘c’ is required for earlier Python versions (see https://docs.python.org/3/library/pdb.html).


回答 2

使用以下模块:

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

Use the following module:

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

Name it debug (or whatever you like) and put it somewhere in your python path.

Now, at the start of your script, just add an import debug.


回答 3

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

Ipython has a command for toggling this behavior: %pdb. It does exactly what you described, maybe even a bit more (giving you more informative backtraces with syntax highlighting and code completion). It’s definitely worth a try!


回答 4

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

我知道我听到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
>>>

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

This isn’t the debugger, but probably just as useful(?)

I know I heard Guido mention this in a speech somewhere.

I just checked python -?, and if you use the -i command you can interact where your script stopped.

So given this script:

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

You can get this output!

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
>>>

To be honest I haven’t used this, but I should be, seems very useful.


回答 5

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的优势。

IPython makes this simple on the command line:

python myscript.py arg1 arg2

can be rewritten to

ipython --pdb myscript.py -- arg1 arg2

Or, similarly, if calling a module:

python -m mymodule arg1 arg2

can be rewritten to

ipython --pdb -m mymodule -- arg1 arg2

Note the -- to stop IPython from reading the script’s arguments as its own.

This also has the advantage of invoking the enhanced IPython debugger (ipdb) instead of pdb.


回答 6

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

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

If you are using ipython, after launching type %pdb

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

回答 7

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

If you are using the IPython environment, you can just use the %debug and the shell will take you back to the offending line with the ipdb environment for inspections etc. Another option as pointed above is to use the iPython magic %pdb which effectively does the same.


回答 8

您可以将以下行放入代码中:

import pdb ; pdb.set_trace()

更多信息:在任意行启动python调试器

You can put this line in your code:

import pdb ; pdb.set_trace()

More info: Start the python debugger at any line


回答 9

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

python -m pdb -c c <script name>

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

To have it run without having to type c at the beginning use:

python -m pdb -c c <script name>

Pdb has its own command line arguments: -c c will execute c(ontinue) command at start of execution and the program will run uninterrupted until the error.


回答 10

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

python -m pdb script.py in python2.7 press continue to start and it will run to the error and break there for debug.


回答 11

如果您正在运行模块:

python -m mymodule

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

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

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

If you are running a module:

python -m mymodule

And now you want to enter pdb when an exception occurs, do this:

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

(or extend your PYTHONPATH). The PYTHONPATH is needed so that the module is found in the path, since you are running the pdb module now.


回答 12

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

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

Put a breakpoint inside the constructor of topmost exception class in the hierarchy, and most of the times you will see where the error was raised.

Putting a breakpoint means whatever you want it to mean : you can use an IDE, or pdb.set_trace, or whatever