使用IPython逐步调试python


Answers

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

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

  1. Emacs中一个新的重要调试器叫做RealGUD ,它可以与任何调试器(包括ipdb )一起运行。
  2. Emacs包isend-mode

这两个软件包的组合非常强大,可以让用户准确地重新创建OP中描述的行为,并做更多工作。

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

原始答案:

在尝试了很多不同的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)

  1. 通过运行一个从Unix shell调用这个函数的Python程序
  2. 或者直接从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对象的任何后续实例化。

Question

从我读到的,有两种方法可以在Python中调试代码:

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

  • 通过在代码中嵌入 IPython shell来使用IPython 。 你可以from ipython import embed做到,然后在你的代码中使用embed() 。 当你的程序/脚本碰到一个embed()语句时,你将被放入一个IPython shell。 这允许使用所有IPython的好东西全面检查对象并测试Python代码。 但是,使用embed()您无法使用方便的键盘快捷方式逐步执行代码。

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

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

MATLAB中进行IPython调试:

在MATLAB中可以找到这种类型的“增强型调试”的例子,用户总是可以完全访问MATLAB引擎/ shell,并且她仍然可以一步一步地通过她的代码,定义条件断点等。我和其他用户讨论过的,这是人们在从MATLAB转向IPython时错过最多的调试功能。

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

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




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

新方法似乎是:

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

def buggy_method():
    debug()



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

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




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




一种选择是使用像Spyder这样的IDE,它可以让你在调试时与你的代码交互(实际上使用IPython控制台)。 事实上,Spyder很像MATLAB,我认为它是有意的。 这包括变量检查器,可变编辑,内置的文档访问等。




从python 3.2开始,您可以使用interact命令,它可以访问完整的python / ipython命令空间。