使用IPython进行Python断点交互式调试

40

假设我有一个IPython会话,从中调用某些脚本:

> run my_script.py

有没有一种方法可以在my_script.py中引发一个断点,以便我可以从IPython检查我的工作环境?

我记得在早期版本的IPython中可以执行以下操作:

from IPython.Debugger import Tracer;     

def my_function():
    x = 5
    Tracer()
    print 5;

但是子模块Debugger似乎不再可用。

假设我已经打开了一个IPython会话:如何在我选择的位置停止我的程序并使用IPython检查我的工作区

一般来说,我更喜欢不需要预先指定行号的解决方案,因为我可能想要在Tracer()之上调用多个此类函数而不必跟踪它们所在的行号。


出于好奇,你为什么会想要同时拥有多个跟踪器?在那种情况下,似乎你应该进行日志记录而不是调试。 - Wilduck
@Wilduck:我想在特定情况下检查我的工作区,而这些情况可能发生在代码的不同位置。 - Amelio Vazquez-Reina
好的,也许我表达得不太清楚。我明白你为什么想要查看代码的不同部分。但是为什么你要在代码中同时设置这些追踪器呢?如果你没有使用调试器来永久地修复一个错误(即一次只修复一个错误),难道不设置日志以自动收集程序在不同状态下运行信息会更好/更容易吗?我之所以问这个问题,是因为你似乎试图将调试工具用于记录日志已经处理了的事情。 - Wilduck
1
谢谢@Wilduck。我对日志记录并不是很感兴趣。我想在满足某些条件时数学地和交互式地检查几个变量的值。我当然可以将变量转储到磁盘并稍后检查它们,但这样做不允许我恢复执行,有时我需要这样做。这种工作流程在科学计算中很常见且强大(例如,MATLAB通过使用“键盘”语句支持此功能),它允许人们交互式地检查和可视化数据,而不会完全干扰或必须重新初始化程序。 - Amelio Vazquez-Reina
1
我明白了,那确实有道理。我会保留我的答案,因为它可能对以后偶然遇到这个问题的人有用,但是很抱歉我没有更多的个人建议给你。祝你好运。 - Wilduck
8个回答

37

Tracer()在IPython中仍然存在,只不过在不同的模块中。您可以执行以下操作:

Tracer()在IPython中仍然存在,只不过在不同的模块中。您可以执行以下操作:

from IPython.core.debugger import Tracer

def my_function():
    x = 5
    Tracer()()
    print 5

请注意在Tracer周围的额外调用括号。

编辑:对于IPython 6及以后的版本,Tracer已经被弃用,因此你应该使用set_trace()代替:

from IPython.core.debugger import set_trace

def my_function():
    x = 5
    set_trace()
    print 5

1
@Arnon 如何使用 set_trace(); 哪个 set_trace?普通的 ipdb.set_trace() 对我来说产生了这个问题,建议使用 Tracer()()!哦,也许是在这里看到的 Pdb.set_trace() 或者 这里;链接的文档描述了 IPython.core.debugger.set_trace,但我没有那个函数。 - Nate Anderson
所链接的文档是针对IPython 6(仅支持Python 3)的,我怀疑您正在使用旧版本。IPython.core.debugger.Tracer在IPython 6中仍然存在并且可以工作,即使已被弃用。我猜您可以继续使用它一段时间,直到它实际上从代码库中删除。 - pankaj
哈哈,没错,我仍在使用“Tracer”,希望有人能描述推荐的替代方案? - Nate Anderson
哎呀,我希望IPython不要每隔几年就改变目标。 - jez
这个答案在当前版本的Python中有问题。 - James Dalgleish

21

您可以运行它,并在给定的行上设置断点:

run -d -b12 myscript

-b12参数将在第12行设置断点。当您输入此行时,将立即进入pdb,并需要输入c以执行到该断点。


谢谢@Wildluck。这个绝对有用,尽管我更感兴趣的是不需要指定行号的东西。 - Amelio Vazquez-Reina

15

使用Python 3 (v3.7+),有一个新的breakpoint()函数。你可以修改它的行为,使它为你调用ipython的调试器。

基本上,你可以设置一个环境变量指向一个调试器函数。(如果你没有设置这个变量,breakpoint()默认调用pdb.)

要将breakpoint()设置为调用ipython的调试器,请在你的shell中设置环境变量如下:

# for bash/zsh users
export PYTHONBREAKPOINT='IPython.core.debugger.set_trace'
# powershell users
$env:PYTHONBREAKPOINT='IPython.core.debugger.set_trace'

(注意,如果您想永久设置环境变量,您需要修改您的shell配置文件或系统偏好设置。)
您可以这样写:
def my_function():
    x = 5
    breakpoint()
    print(5)

它将为您打开ipython的调试器。我认为这比需要导入from IPython.core.debugger import set_trace并调用set_trace()更方便。


在我的 requirements.txt 文件中添加 ipython==8.8.0 可以让我在 pdb 中使用 ipython。 - Harry Moreno

13

这是使用set_trace()方法而不是已弃用的Tracer()方法的版本。

from IPython.core.debugger import Pdb

def my_function():
    x = 5
    Pdb().set_trace()
    print 5

我想把这个答案作为评论添加到上面被接受的答案中,但是我没有足够的声望来发表评论,所以我希望如果这个答案对任何人有帮助的话。 - Medhat Omr
1
另外,您也可以直接使用 IPython.core.debugger.set_trace() 而不需要 Pdb - Keith Prussing

9
在IPython shell中,您可以执行以下操作:
from IPython.core.debugger import Pdb
pdb = Pdb()
pdb.runcall(my_function)

例如,在函数内部使用常规的 pdb.set_trace()

1
谢谢,但第一个解决方案并不清楚如何让我指定断点的可能位置。至于第二个解决方案,我该如何实际使用该选项?最后,据我所知,pdb不能像IPython那样提供内省等功能。这正确吗? - Amelio Vazquez-Reina
一旦启动调试器,您可以使用 b pdb 命令来定义断点。 - Kos

5

我一直有同样的问题,而我找到的最好的解决方法是添加一行会破坏我的代码的代码,就像这样:

...
a = 1+2
STOP
...

当我运行这段代码时,它会中断,然后我可以使用%debug去检查并解决问题。您还可以打开%pbd来始终跳转到代码中断的位置,但如果您不想在每次代码中断时都进行检查,这可能会很麻烦。我希望有一个更优雅的解决方案。


0

我看到了很多选项,但也许没有以下简单的选项。 在my_script.py所在的目录中启动ipython。 如果您希望代码在失败时进入调试模式,请打开调试器。键入%pdb

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

下一个类型

In [2]: %run -d ./my_script.py
*** Blank or comment
*** Blank or comment
NOTE: Enter 'c' at the ipdb>  prompt to continue execution.
> c:\users\c81196\lgd\mortgages-1\nmb\lgd\run_lgd.py(2)<module>()
      1 # system imports
----> 2 from os.path import join

现在您可以在任何地方设置断点。 输入b 100在第100行设置断点,或者输入b whatever.py:102whatever.py文件的第102行设置断点。 例如:
ipdb> b 100

然后继续运行,或者继续。

ipdb> c

一旦代码失败或到达断点,您可以开始使用Python调试器 pdb 的全部功能。

请注意,pdb 还允许在函数处设置断点。

b(reak) [([filename:]lineno | function) [, condition]]

所以你不一定需要使用行号。


0
如果你正在使用pytest,那么
pip install ipython
pip install ipdb
# run tests with options
pytest --pdb --pdbcls=IPython.terminal.debugger:TerminalPdb

# or set it in pytest.ini
[pytest]
addopts = --pdbcls=IPython.terminal.debugger:TerminalPdb


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接