关于python:使用IPython逐步调试

Step-by-step debugging with IPython

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

  • 使用传统的调试器,如pdbipdb。它支持诸如continuecstep-overnsstep-into等命令,但您不能直接访问ipython外壳,这对于对象检查非常有用。

  • 通过在代码中嵌入ipython外壳来使用ipython。您可以执行from ipython import embed,然后在代码中使用embed()。当程序/脚本命中embed()语句时,您将被放入ipython shell中。这允许使用所有的ipython goodies对对象进行全面检查和测试python代码。但是,当使用embed()时,您不能再使用方便的键盘快捷键逐步地浏览代码了。

有没有办法把两个世界的精华结合起来?即。

  • 使用方便的PDB/IPDB键盘快捷键,可以一步一步地完成代码。
  • 在任何这样的步骤(例如在给定的语句上),都可以访问成熟的ipython shell。
  • 在matlab中进行ipython调试:

    在Matlab中可以找到这种"增强调试"的一个例子,用户总是可以完全访问Matlab引擎/shell,而且她仍然可以一步一步地通过她的代码,定义条件断点等。根据我与其他用户讨论的内容,这是从Matlab迁移时人们最怀念的调试功能。伊普敦。

    Emacs和其他编辑器中的ipython调试:

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


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

    埃多克斯1〔3〕

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

    这允许对代码进行全面检查,并且您可以访问诸如EDOCX1(continue)、EDOCX1(execute next line)、EDOCX1(step into the method at point)等命令。

    请参阅ipdb repo和命令列表。伊普利顿现在被称为朱彼特。

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

    另外,如果您喜欢ipython提示(它的emacs和vim模式、历史、完成等等),那么很容易为您的项目获得相同的结果,因为它是基于python提示工具包的。


    (2016年5月28日更新)在emacs中使用realgud

    对于Emacs中的任何人,此线程将演示如何使用

  • Emacs中一个新的重要调试器,叫做realgud,它可以与任何调试器(包括ipdb一起操作)。
  • Emacs包isend-mode
  • 这两个包的组合是非常强大的,它允许您准确地重新创建OP中描述的行为,并执行更多操作。

    有关IPDB的realgud wiki文章的更多信息。

    原始答案:

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

    定义自定义嵌入的IPython外壳:

    在脚本中添加以下内容到您的PYTHONPATH中,这样方法ipsh()就可用了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    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 = ("
    **Nested Interpreter:
    "

    "Hit Ctrl-D to exit interpreter and continue program.
    "

    "Note that if you use %kill_embedded, you can fully deactivate
    "

    "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

    使用它:

    1
    2
    3
    4
    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 shell的常规ipython运行代码(上面的案例2),那么新的ipython shell将嵌套在调用它的ipython shell中,这是非常好的,但最好注意。另外,一旦解释器停在ipsh的位置,我可以检查a的值(即2的值),查看定义了什么函数和对象等。

    问题是:

    上面的解决方案可以用于让python在代码中的任何地方停止,然后将您放入一个成熟的ipython解释器中。不幸的是,它不允许您在调用脚本后添加或删除断点,这非常令人沮丧。在我看来,这是唯一一件阻止ipython成为Python调试工具的事情。

    你现在能做的最好的:

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

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


    还没有人提到过伊普顿的%pdb旗。只需在ipython中调用%pdb,当出现错误时,您将自动转到ipdb。虽然你没有马上踏上台阶,但之后你就进入了江户十一〔二〕。

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


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

    顺便说一句,IPDB在幕后使用IPython,实际上您可以使用IPython功能,例如制表完成和magic命令(其中一个以%开头)。如果您对IPDB没有问题,可以使用%run%debug等命令从ipython启动它。IPDB会话实际上比普通的IPython会话更好,从这个意义上说,您可以在堆栈跟踪等中上下移动。IPDB中"对象检查"缺少什么?

    另外,与emacs>=24.3捆绑在一起的python.el具有很好的IPDB支持。


    看来@gaborous答案中的方法已被否决。

    新方法似乎是:

    1
    2
    3
    4
    5
    from IPython.core import debugger
    debug = debugger.Pdb().set_trace

    def buggy_method():
        debug()


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

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

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


    你试过这个提示吗?

    Or better still, use ipython, and call:

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

    then you can just use

    1
    debug_here()

    whenever you want to set a breakpoint


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

    1
    2
    3
    4
    5
    6
    7
    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


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


    PYZO IDE的功能与OP要求的功能相似。您不必在调试模式下启动。与matlab类似,命令在shell中执行。当您在一些源代码行中设置断点时,IDE会在那里停止执行,您也可以调试和发出常规的ipython命令。

    不过,似乎进入这一步(还没有?)除非您设置了另一个断点,否则工作良好(即在一行中停止,然后进入另一个函数)。

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


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


    在python 3.2中,您有interact命令,它允许您访问完整的python/ipython命令空间。


    从Emacs的ipython shell内部运行,并通过pdb.set_trace()设置断点。

    使用python-mode.el、m-x ipython ret等进行检查。