用IPython逐步debugging

从我读到的,有两种方法来在Python中debugging代码:

  • 使用传统的debugging器,如pdbipdb 。 这支持命令,例如c continuenstep-oversstep-into等等),但是你不能直接访问IPython shell,这对于对象检查是非常有用的。

  • 通过在代码中embedded IPython shell来使用IPython 。 你可以from ipython import embed来做,然后在你的代码中使用embed() 。 当你的程序/脚本碰到一个embed()语句时,你被放到一个IPython shell中。 这允许使用所有IPython的好东西全面检查对象并testingPython代码。 但是,在使用embed()您不能一步一步地通过代码来使用方便的键盘快捷键。

有什么办法可以把两全其美? 即

  1. 使用方便的pdb / ipdb键盘快捷键,可以一步一步通过代码。
  2. 在任何这样的步骤(例如,在一个给定的语句),可以访问一个完整的IPython shell

MATLAB中进行IPythondebugging:

在MATLAB中可以find这种types的“增强型debugging”的例子,在那里用户总是可以完全访问MATLAB引擎/ shell,她仍然可以一步一步地通过她的代码,定义条件断点等。我已经和其他用户讨论过,这是人们从MATLAB转移到IPython时错过最多的debuggingfunction。

在Emacs和其他编辑器中进行IPythondebugging:

我不想让这个问题太具体,但我主要在Emacs工作,所以我想知道是否有任何方法将这个function。 理想情况下 ,Emacs(或编辑器)将允许程序员在代码的任何位置设置断点,并与解释器或debugging器进行通信,使其停止在您select的位置,并在该位置带上一个完整的IPython解释器。

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

import ipdb; ipdb.set_trace()

这允许对代码进行全面检查,并且可以访问c (continue), n (执行下一行), s (进入方法)等命令。

请参阅ipdb repo和命令列表 。 IPython现在被称为(编辑: Jupyter的一部分)。


ps:请注意,ipdb命令优先于Python代码。 所以为了写list(foo)你需要print list(foo)

另外,如果你喜欢ipython的提示符(它的emacs和vim模式,历史,完成,…),它很容易让你的项目相同,因为它是基于python提示工具包 。

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

对于Emacs中的任何人来说, 这个线程展示了如何使用OP(以及更多)完成描述的所有内容

  1. Emacs中一个新的重要的debugging器叫做RealGUD ,可以和任何debugging器(包括ipdb )一起工作。
  2. Emacs包isend-mode

这两个软件包的结合是非常强大的,可以让用户准确地重新创buildOP中描述的行为,甚至可以做到更多。

关于ipdb的RealGUD wiki文章的更多信息。


原始答案:

在尝试了很多不同的方法来debuggingPython之后,包括在这个线程中提到的所有东西之后,用IPythondebuggingPython的首选方法之一就是embedded式shell。

定义一个定制的embedded式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) 

然后,每当我想在我的代码中debugging某些东西时,我将ipsh()放在需要进行对象检查的位置等等。例如,假设我想在下面debuggingmy_function

使用它:

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

然后通过以下方式之一调用my_function(2)

  1. 通过运行一个从Unix shell调用这个函数的Python程序
  2. 或者直接从IPython调用它

无论我如何调用它,解释器停在说ipsh() 。 一旦你完成,你可以做Ctrl-D和Python将恢复执行(与您所做的任何variables更新)。 请注意,如果您从IPython IPython shell(上面的第2种情况)运行代码,则新的IPython shell将嵌套在您调用它的那个内部,这非常好,但是很好理解。 无论如何,一旦解释器停在ipsh的位置,我可以检查a (它是2 )的值,看看定义了什么函数和对象等等。

问题:

上面的解决scheme可以用来让Python在代码中的任何地方停下来,然后把你放到一个完整的IPython解释器中。 不幸的是,一旦你调用脚本,它不会让你添加或删除断点,这是非常令人沮丧的。 在我看来,这是阻止IPython成为Python的一个很好的debugging工具的唯一的东西。

你现在可以做的最好的:

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

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

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

顺便说一下,ipdb在后台使用IPython,你可以实际使用IPython的function,如TAB完成和魔术命令(以%开头)。 如果您使用ipdb可以,您可以使用命令(如%run%debug从IPython启动它。 ipdb会话实际上比普通IPython更好,您可以在堆栈跟踪等中进行上下传递。ipdb中缺less“对象检查”function吗?

另外,与Emacs> = 24.3捆绑在一起的python.el具有良好的ipdb支持。

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

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

但!help(numpy.transpose)会给你numpy.transpose预期的帮助页面。 同样,对于variables名称,假设你有一个variablesl,在pdb中键入“l”列出了代码,但是!l打印出l的值。

看起来像@ gaborous的答案中的方法已被弃用 。

新方法似乎是:

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

没有人提到IPython的%pdb标志呢。 只需在IPython中调用%pdb ,并在发生错误时自动将其删除到ipdb 。 虽然你没有立即步进,你以后在ipdb

这使得debugging单个函数变得简单,因为你可以只加载一个带有%load的文件,然后运行一个函数。 你可以在正确的位置assert一个错误。

你试过这个提示吗?

或者更好的是,使用ipython,然后调用:

 from IPython.Debugger import Tracer; debug_here = Tracer() 

那么你可以使用

 debug_here() 

每当你想设置一个断点

一种select是使用像Spyder这样的IDE,它允许你在debugging的时候和你的代码进行交互(事实上使用IPython控制台)。 事实上,Spyder是非常类似于MATLAB的,我认为这是有意的。 这包括variables检查器,可变编辑,内置的文档访问等。

如果在embed()控制台中inputexit(),则代码继续并转到下一个embed()行。

Pyzo IDE与OP要求的function类似。 您不必以debugging模式启动。 类似于MATLAB,这些命令在shell中执行。 在某些源代码行中设置断点时,IDE会停止执行,您也可以debugging并发出常规的IPython命令。

然而,看起来步入式还没有(还没有)工作得很好(即停在一条线上,然后进入另一个function),除非你设置了另一个断点。

不过,来自MATLAB,这似乎是我find的最好的解决scheme。

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

用python-mode.el,Mx,ipython等检查