ChatGPT解决这个技术问题 Extra ChatGPT

使用 IPython 逐步调试

根据我的阅读,有两种方法可以在 Python 中调试代码:

使用传统的调试器,例如 pdb 或 ipdb。这支持诸如 c 表示继续、n 表示步进、s 表示步进等命令),但您无法直接访问 IPython shell,这对于对象检查非常有用。

通过在代码中嵌入 IPython shell 来使用 IPython。您可以从 IPython 导入嵌入,然后在代码中使用 embed()。当您的程序/脚本遇到 embed() 语句时,您将被放入 IPython shell。这允许使用所有 IPython 好东西来全面检查对象和测试 Python 代码。但是,当使用 embed() 时,您不能再使用方便的键盘快捷键逐步完成代码。

有什么方法可以结合两全其美? IE

能够使用方便的 pdb/ipdb 键盘快捷键逐步完成您的代码。在任何这样的步骤(例如,在给定的语句上),都可以访问成熟的 IPython shell。

在 MATLAB 中进行 IPython 调试:

可以在 MATLAB 中找到此类“增强调试”的示例,其中用户始终可以完全访问 MATLAB 引擎/shell,并且她仍然可以逐步完成她的代码、定义条件断点等。我和其他用户讨论过的,这是人们从 MATLAB 迁移到 IPython 时最怀念的调试功能。

在 Emacs 和其他编辑器中进行 IPython 调试:

我不想让这个问题太具体,但我主要在 Emacs 中工作,所以我想知道是否有任何方法可以将这个功能引入其中。理想情况下,Emacs(或编辑器)将允许程序员在代码的任何位置设置断点,并与解释器或调试器通信,使其停在您选择的位置,并在该位置引入完整的 IPython 解释器。

pdb 有 ! 命令在断点处执行任何 python 命令
我也在寻找一个类似于 Matlab 的 python 调试器!例如,我在 python shell 中做了很多原型设计。所有变量都保存在 shell 中。现在我遇到了一个问题。我希望调试一小段代码,用shell计算出的变量。但是,新的调试器无法访问旧变量。原型制作不方便。
对于 Emacs 用户,RealGUD 有一个非常好的界面。
谢谢@Clément,上个月我一直在关注回购,我对这个项目感到非常兴奋:) 我还没有尝试过,但是一旦我这样做(或者如果你这样做了),请随时在这里写一个答案,也许展示了如何完成所要求的。供其他人参考,网址为 github.com/rocky/emacs-dbgr
@Clément 另外,如果您对 RealGUD 有任何经验ipdb,我尝试按照此处 github.com/rocky/emacs-dbgr/issues/96 的说明使用它,但没有运气。

C
CharlesB

ipdb.set_trace() 怎么样?在您的代码中:

import ipdb; ipdb.set_trace()

更新:现在在 Python 3.7 中,我们可以编写 breakpoint()。它的工作原理相同,但它也服从 PYTHONBREAKPOINT 环境变量。此功能来自 this PEP

这允许对您的代码进行全面检查,并且您可以访问诸如 c(继续)、n(执行下一行)、s(进入该方法)等命令。

请参阅 ipdb repoa list of commandsIPython 现在称为(编辑:部分)Jupyter

ps:请注意,ipdb 命令优先于 python 代码。因此,要编写 list(foo),您需要 print(list(foo))!list(foo)

此外,如果您喜欢 ipython 提示符(它的 emacs 和 vim 模式、历史记录、完成...),您的项目很容易获得相同的提示,因为它基于 python prompt toolkit


这是做到这一点的方法。
我现在的答案包括如何在 Emacs 中使用 ipdb 使用 RealGUDisend-mode 来完全按照 OP 的要求进行操作。
Jupyter 不是 IPython 的替代品,而是 IPython Notebook 的替代品。 Jupyter notebooks 在后台使用内核。对于 Python notebook,内核通常是 IPython 内核。 IPython project 继续。
breakpoint() 很棒。在 PyCharm 中,它甚至会将您放入 PyCharm 调试器中。这也是从粘贴到控制台的函数中进入 PyCharm 调试器的快速方法。
更新后我可以简单地设置环境变量 PYTHONBREAKPOINT=IPython.embed 然后 breakpoint() 将完成这项工作
m
mit

您可以使用 IPython 的 %pdb magic。只需在 IPython 中调用 %pdb,当发生错误时,您会自动转到 ipdb。虽然您没有立即进行步进,但您在 ipdb 之后。

这使得调试单个函数变得容易,因为您只需使用 %load 加载文件,然后运行函数。您可以在正确的位置使用 assert 强制出错。

%pdb 是一个线魔法。将其称为 %pdb on%pdb 1%pdb off%pdb 0。如果在没有参数的情况下调用它,它将作为切换。


^ 这才是真正的答案
是否有类似的东西 pdb 具有类似 IPython 的功能而最初不在 IPython 中?
您也可以使用 ipython --pdb file.py -- args 启动程序,并在出现异常时将其丢弃到 ipdb。可能值得添加到答案中。
C
Community

(2016 年 5 月 28 日更新)在 Emacs 中使用 RealGUD

对于 Emacs 中的任何人,this thread 展示了如何使用

Emacs 中一个新的重要调试器,称为 RealGUD,它可以与任何调试器(包括 ipdb)一起运行。 Emacs 包是end-mode。

这两个包的组合是非常强大的,它允许一个人准确地重新创建 OP 中描述的行为并做更多的事情。

有关 RealGUD for ipdb 的 the wiki article 的更多信息。

原答案:

在尝试了许多不同的 Python 调试方法(包括本线程中提到的所有内容)之后,我使用 IPython 调试 Python 的首选方法之一是使用嵌入式 shell。

定义一个自定义的嵌入式 IPython shell:

将以下脚本添加到您的 PYTHONPATH,以便方法 ipsh() 可用。

import inspect

# First import the embed function
from IPython.terminal.embed import InteractiveShellEmbed
from IPython.config.loader import Config

# Configure the prompt so that I know I am in a nested (embedded) shell
cfg = Config()
prompt_config = cfg.PromptManager
prompt_config.in_template = 'N.In <\\#>: '
prompt_config.in2_template = '   .\\D.: '
prompt_config.out_template = 'N.Out<\\#>: '

# Messages displayed when I drop into and exit the shell.
banner_msg = ("\n**Nested Interpreter:\n"
"Hit Ctrl-D to exit interpreter and continue program.\n"
"Note that if you use %kill_embedded, you can fully deactivate\n"
"This embedded instance so it will never turn on again")   
exit_msg = '**Leaving Nested interpreter'

# Wrap it in a function that gives me more context:
def ipsh():
    ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg)

    frame = inspect.currentframe().f_back
    msg   = 'Stopped at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame)

    # Go back one level! 
    # This is needed because the call to ipshell is inside the function ipsh()
    ipshell(msg,stack_depth=2)

然后,每当我想调试代码中的某些内容时,我都会将 ipsh() 放在我需要进行对象检查等的位置。例如,假设我想在下面调试 my_function

使用它:

def my_function(b):
  a = b
  ipsh() # <- This will embed a full-fledged IPython interpreter
  a = 4

然后我以下列方式之一调用 my_function(2)

通过运行从 Unix shell 调用此函数的 Python 程序或直接从 IPython 调用它

无论我如何调用它,解释器都会停在 ipsh() 行。完成后,您可以执行 Ctrl-D,Python 将继续执行(使用您所做的任何变量更新)。请注意,如果您从常规 IPython IPython shell(上面的案例 2)运行代码,新的 IPython shell 将 嵌套 在您调用它的那个中,这非常好,但是很高兴知道。不管怎样,一旦解释器停在 ipsh 的位置,我就可以检查 a 的值(即 2),查看定义了哪些函数和对象等。

问题:

上面的解决方案可用于让 Python 在代码中的任何位置停止,然后将您放入成熟的 IPython 解释器。不幸的是,一旦调用脚本,它就不允许您添加或删除断点,这非常令人沮丧。在我看来,这是阻止 IPython 成为 Python 的出色调试工具的唯一原因。

你现在能做的最好的事情:

一种解决方法是将 ipsh() 先验放置在您希望 Python 解释器启动 IPython shell 的不同位置(即 breakpoint)。然后,您可以使用 Ctrl-D 在不同的预定义硬编码“断点”之间“跳转”,这将退出当前嵌入式 IPython shell,并在解释器下一次调用 ipsh() 时再次停止。

如果您走这条路,退出“调试模式”并忽略所有后续断点的一种方法是使用 ipshell.dummy_mode = True,这将使 Python 忽略我们在上面创建的 ipshell 对象的任何后续实例化。


每当您找到更好的解决方案时,请更新此内容。但这看起来很棒。我会用它。
您在哪里/如何定义/导入 cfg、banner_msg、exit_msg 和检查?
我需要在它起作用之前添加 import inspect。不过,命令行自定义对我来说似乎被打破了。
为什么不直接使用 import ipdb; ipdb.set_trace()?也许我错过了一些东西,但我没有看到你更复杂的方法的优势。
t
tkf

您可以从 pudb 启动 IPython 会话,然后根据需要返回调试会话。

顺便说一句,ipdb 在幕后使用 IPython,您实际上可以使用 IPython 功能,例如 TAB 完成和魔术命令(以 % 开头的命令)。如果您对 ipdb 没问题,您可以使用 %run%debug 等命令从 IPython 启动它。 ipdb 会话实际上比普通的 IPython 会话更好,因为您可以在堆栈跟踪等中上下移动。ipdb 中缺少什么用于“对象检查”?

此外,与 Emacs >= 24.3 捆绑的 python.el 具有很好的 ipdb 支持。


谢谢tkf。我是您的 Emacs-Jedi 软件包的忠实粉丝。当您说 Emacs 24.3 对 ipdb 有很好的支持时,您介意详细说明一下吗?我通常在单独的 M-x ansi-term 缓冲区中启动 IPython,然后使用 isend-mode 将源缓冲区绑定到 IPython 缓冲区,以便我可以使用键盘快捷键将代码发送到 IPython 解释器,该快捷键会自动发送 %paste 魔法到 IPython 缓冲区。这让我可以在 IPython 中快速测试区域。我总是使用 run 从这个 IPython shell 运行我的程序并使用 embed() 停止。
例如,当您单步执行代码时,源代码在另一个缓冲区中打开,箭头指向当前执行点。你也有 send-region 命令,就像你使用 isend-mode 一样。
谢谢@tkf 如何使用 python.el 启动 ipdb 调试会话并将 send-region 等内容添加到相应的 shell?一般来说,我在哪里可以找到有关此的更多信息?
我使用 %run%debug。我猜 import ipdb; ipdb.set_trace() 也可以。我认为您不能将多行发送到 ipdb。这是 ipdb 的限制。但可能 %paste 技巧有效。您可能希望向 IPython 开发人员发送功能请求。
E
Elliot Larson

看起来像@gaborous 的回答 is deprecated 中的方法。

新方法似乎是:

from IPython.core import debugger
debug = debugger.Pdb().set_trace

def buggy_method():
    debug()

这是否允许您在调试时在 ipython shell 中使用 ipdb 语句?
u
user1953384

前缀“!”您在 pdb 中键入的命令的符号似乎与在 IPython shell 中执行某些操作具有相同的效果。这适用于访问某个函数的帮助,甚至是变量名。也许这会在一定程度上帮助你。例如,

ipdb> help(numpy.transpose)
*** No help on (numpy.transpose)

但是 !help(numpy.transpose) 将为您提供有关 numpy.transpose 的预期帮助页面。同样对于变量名称,假设您有一个变量 l,在 pdb 中键入“l”会列出代码,但 !l 会打印 l 的值。


这是一个令人讨厌的 pdb 陷阱,非常值得了解。
L
Lorem Ipsum

您可以IPython 从内部 ipdb 开始。

诱导 ipdb 调试器1

import idpb; ipdb.set_trace()

ipdb> 控制台2从内部输入 IPython:

from IPython import embed; embed()

IPython 中返回到 ipdb> 控制台:

exit

如果你有幸使用 Emacs,事情会变得更加方便。

这需要使用 M-x shell。使用 yasnippetbm,定义以下代码段。这会将编辑器中的文本 ipdb 替换为 set-trace 行。插入代码段后,该行将被突出显示,以便它容易被注意到和导航。使用 M-x bm-next 导航。

# -*- mode: snippet -*-
# name: ipdb
# key: ipdb
# expand-env: ((yas-after-exit-snippet-hook #'bm-toggle))
# --
import ipdb; ipdb.set_trace()

1 全部在一行,便于删除。由于 imports 只发生一次,因此此表单可确保在您需要时导入 ipdb,而不会产生额外开销。

2 您可以通过导入 IPython within your .pdbrc file 节省一些输入:

try:
    from IPython import embed
except:
    pass

这允许您从 ipdb 中简单地调用 embed()(当然,只有在安装了 IPython 时)。


g
gaborous

你试过 this tip 吗?

或者更好的是,使用 ipython,然后调用: from IPython.Debugger import Tracer; debug_here = Tracer() 那么只要你想设置断点就可以使用 debug_here()


ModuleNotFoundError: No module named 'IPython.Debugger'
@JohnGreene 这是一个非常古老的答案,现在 IPython 已重命名为 Jupyter,API 发生了很大变化。
P
Ping

该问题的正确、简单、酷、准确的答案是使用带有 -d 标志的 %run 宏。

In [4]: run -d myscript.py
NOTE: Enter 'c' at the ipdb>  prompt to continue execution.        
> /cygdrive/c/Users/mycodefolder/myscript.py(4)<module>()
      2                                                            
      3                        
----> 4 a=1                                            
      5 b=2

这应该更高。如果我需要在我的代码中插入一行(在模块内),我需要重新启动 IPython 以重新加载模块。有了这个,我只需 %save /tmp/foo.py x-y 我想要运行和调试的代码,然后 %run -d /tmp/foo.py 在任何我喜欢的地方设置断点。很好的答案!
B
Benjamin B.

一种选择是使用像 Spyder 这样的 IDE,它应该允许您在调试时与代码交互(实际上是使用 IPython 控制台)。事实上,Spyder 非常类似于 MATLAB,我认为这是故意的。这包括变量检查器、变量编辑、对文档的内置访问等。


T
TurinTurambar

如果您在 embed() 控制台中键入 exit(),代码将继续并转到下一个 embed() 行。


u
user6715080

Pyzo IDE 具有与 OP 要求类似的功能。您不必在调试模式下启动。与 MATLAB 类似,命令在 shell 中执行。当您在某个源代码行中设置断点时,IDE 会在那里停止执行,您也可以调试和发出常规 IPython 命令。

然而,除非您设置另一个断点,否则单步执行似乎(还没有?)效果很好(即在一行中停止然后进入另一个函数)。

不过,来自 MATLAB,这似乎是我找到的最佳解决方案。


a
alpha_989

从 python 3.2 开始,您拥有 interact 命令,可让您访问完整的 python/ipython 命令空间。


A
Andreas Röhler

从 Emacs 的 IPython-shell 内部运行并通过 pdb.set_trace() 设置断点应该可以工作。

用 python-mode.el、Mx ipython RET 等检查。


S
SwimBikeRun

开发新代码

在 IPython 中调试

使用 Jupyter/IPython 单元执行来加速实验迭代使用 %%debug 进行单步执行

单元格示例:

%%debug
...: for n in range(4):
...:    n>2

调试现有代码

IPython里面调试

调试损坏的单元测试:pytest ... --pdbcls=IPython.terminal.debugger:TerminalPdb --pdb 在测试用例之外调试:breakpoint()、python -m ipdb 等 IPython.embed() 用于完整的 IPython 功能在调试器中需要的地方

对 Python 的思考

我同意 OP 的观点,即 MATLAB 做得很好 Python 仍然没有而且确实应该做的很多事情,因为该语言中的几乎所有内容都倾向于开发速度而不是生产速度。也许有一天我会为 CPython 贡献比琐碎的错误修复更多的东西。

https://github.com/ipython/ipython/commit/f042f3fea7560afcb518a1940daa46a72fbcfa68

另请参阅Is it possible to run commands in IPython with debugging?