使用 IPython 逐步调试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16867347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 23:52:23  来源:igfitidea点击:

Step-by-step debugging with IPython

pythondebuggingemacsipythonpdb

提问by Amelio Vazquez-Reina

From what I have read, there are two ways to debug code in Python:

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

  • With a traditional debugger such as pdbor ipdb. This supports commands such as cfor continue, nfor step-over, sfor step-intoetc.), but you don't have direct access to an IPython shell which can be extremely useful for object inspection.

  • Using IPythonby embeddingan IPython shell in your code. You can do from ipython import embed, and then use embed()in your code. When your program/script hits an embed()statement, you are dropped into an IPython shell. This allows the full inspection of objects and testing of Python code using all the IPython goodies. However, when using embed()you can't step-by-stepthrough the code anymore with handy keyboard shortcuts.

  • 使用传统的调试器,例如pdbipdb。这支持诸如cfor continuenfor step-oversforstep-into等命令),但您无法直接访问对对象检查非常有用的 IPython shell。

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

Is there any way to combine the best of both worlds? I.e.

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

  1. Be able to step-by-stepthrough your code with handy pdb/ipdb keyboard shortcuts.
  2. At any such step (e.g. on a given statement), have access to a full-fledged IPython shell.
  1. 能够 使用方便的 pdb/ipdb 键盘快捷键逐步完成您的代码。
  2. 在任何这样的步骤(例如在给定的语句上),都可以访问成熟的IPython shell

IPython debugging as inMATLAB:

IPython的调试MATLAB:

An example of this type of "enhanced debugging" can be found in MATLAB, where the user alwayshas full access to the MATLAB engine/shell, and she can still step-by-stepthrough her code, define conditional breakpoints, etc. From what I have discussed with other users, this is the debugging feature that people miss the most when moving from MATLAB to IPython.

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

IPython debugging in Emacs and other editors:

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

I don't want to make the question too specific, but I work mostly in Emacs, so I wonder if there is any way to bring this functionality into it. Ideally, Emacs (or the editor) would allow the programmer to set breakpoints anywhere on the code and communicate with the interpreter or debugger to have it stop in the location of your choice, and bring to a full IPython interpreter on that location.

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

采纳答案by sebastian

You can use IPython's %pdbmagic. Just call %pdbin IPython and when an error occurs, you're automatically dropped to ipdb. While you don't have the stepping immediately, you're in ipdbafterwards.

你可以使用 IPython 的%pdb魔法。只需调用%pdbIPython,当发生错误时,您将自动跳转到ipdb. 虽然您没有立即踩踏,但您ipdb之后就进入了。

This makes debugging individual functions easy, as you can just load a file with %loadand then run a function. You could force an error with an assertat the right position.

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

%pdbis a line magic. Call it as %pdb on, %pdb 1, %pdb offor %pdb 0. If called without argument it works as a toggle.

%pdb是行魔法。呼之为%pdb on%pdb 1%pdb off%pdb 0。如果不带参数调用它作为一个切换。

回答by Amelio Vazquez-Reina

One option is to use an IDE like Spyderwhich should allow you to interact with your code while debugging (using an IPython console, in fact). In fact, Spyder is very MATLAB-like, which I presume was intentional. That includes variable inspectors, variable editing, built-in access to documentation, etc.

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

回答by Andreas R?hler

Running from inside Emacs' IPython-shell and breakpoint set via pdb.set_trace() should work.

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

Checked with python-mode.el, M-x ipython RET etc.

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

回答by tkf

You can start IPython session from pudband go back to the debugging session as you like.

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

BTW, ipdb is using IPython behind the scenes and you can actually use IPython functionality such as TAB completion and magic commands (the one starts with %). If you are OK with ipdb you can start it from IPython using commands such as %runand %debug. ipdb session is actually better than plain IPython one in the sense you can go up and down in the stack trace etc. What is missing in ipdb for "object inspection"?

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

Also, python.el bundled with Emacs >= 24.3 has nice ipdb support.

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

回答by Ehvince

What about ipdb.set_trace() ? In your code :

ipdb.set_trace() 呢?在您的代码中:

import ipdb; ipdb.set_trace()

import ipdb; ipdb.set_trace()

update: now in Python 3.7, we can write breakpoint(). It works the same, but it also obeys to the PYTHONBREAKPOINTenvironment variable. This feature comes from this PEP.

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

This allows for full inspection of your code, and you have access to commands such as c(continue), n(execute next line), s(step into the method at point) and so on.

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

See the ipdb repoand a list of commands. IPythonis now called (edit: part of) Jupyter.

请参阅ipdb 存储库命令列表IPython现在被称为(编辑:一部分)Jupyter



ps: note that an ipdb command takes precedence over python code. So in order to write list(foo)you'd need print list(foo).

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

Also, if you like the ipython prompt (its emacs and vim modes, history, completions,…) it's easy to get the same for your project since it's based on the python prompt toolkit.

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

回答by user1953384

Prefixing an "!" symbol to commands you type in pdb seems to have the same effect as doing something in an IPython shell. This works for accessing help for a certain function, or even variable names. Maybe this will help you to some extent. For example,

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

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

But !help(numpy.transpose) will give you the expected help page on numpy.transpose. Similarly for variable names, say you have a variable l, typing "l" in pdb lists the code, but !l prints the value of l.

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

回答by Amelio Vazquez-Reina

(Update on May 28, 2016) Using RealGUD in Emacs

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

For anyone in Emacs, this threadshows how to accomplish everything described in the OP (and more) using

对于 Emacs 中的任何人,该线程展示了如何使用

  1. a new important debugger in Emacs called RealGUDwhich can operate with any debugger (including ipdb).
  2. The Emacs package isend-mode.
  1. Emacs 中一个新的重要调试器,称为RealGUD,它可以与任何调试器(包括ipdb)一起运行。
  2. Emacs 包isend-mode

The combination of these two packages is extremely powerful and allows one to recreate exactly the behavior described in the OP and do even more.

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

More info on the wiki articleof RealGUD for ipdb.

有关ipdb 的 RealGUD维基文章的更多信息。



Original answer:

原答案:

After having tried many different methods for debugging Python, including everything mentioned in this thread, one of my preferred ways of debugging Python with IPython is with embedded shells.

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

Defining a custom embedded IPython shell:

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

Add the following on a script to your PYTHONPATH, so that the method ipsh()becomes available.

将以下脚本添加到您的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)

Then, whenever I want to debug something in my code, I place ipsh()right at the location where I need to do object inspection, etc. For example, say I want to debug my_functionbelow

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

Using it:

使用它:

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

and then I invoke my_function(2)in one of the following ways:

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

  1. Either by running a Python program that invokes this function from a Unix shell
  2. Or by invoking it directly from IPython
  1. 通过运行从 Unix shell 调用此函数的 Python 程序
  2. 或者直接从 IPython 调用它

Regardless of how I invoke it, the interpreter stops at the line that says ipsh(). Once you are done, you can do Ctrl-Dand Python will resume execution (with any variable updates that you made). Note that, if you run the code from a regular IPython the IPython shell (case 2 above), the new IPython shell will be nestedinside the one from which you invoked it, which is perfectly fine, but it's good to be aware of. Eitherway, once the interpreter stops on the location of ipsh, I can inspect the value of a(which be 2), see what functions and objects are defined, etc.

不管我如何调用它,解释器都会停在说ipsh(). 完成后,您可以执行操作Ctrl-D,Python 将继续执行(包括您所做的任何变量更新)。请注意,如果您从常规 IPython 的 IPython 外壳(上面的情况 2)运行代码,新的 IPython 外壳将嵌套在您从中调用它的外壳中,这很好,但最好注意。无论哪种方式,一旦解释器停在 的位置ipsh,我就可以检查a(which be 2)的值,查看定义了哪些函数和对象等。

The problem:

问题:

The solution above can be used to have Python stop anywhere you want in your code, and then drop you into a fully-fledged IPython interpreter. Unfortunately it does not let you add or remove breakpoints once you invoke the script, which is highly frustrating. In my opinion, this is the onlything that is preventing IPython from becoming a great debugging tool for Python.

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

The best you can do for now:

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

A workaround is to place ipsh()a priori at the different locations where you want the Python interpreter to launch an IPython shell (i.e. a breakpoint). You can then "jump" between different pre-defined, hard-coded "breakpoints" with Ctrl-D, which would exit the current embedded IPython shell and stop again whenever the interpreter hits the next call to ipsh().

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

If you go this route, one way to exit "debugging mode" and ignore all subsequent breakpoints, is to use ipshell.dummy_mode = Truewhich will make Python ignore any subsequent instantiations of the ipshellobject that we created above.

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

回答by gaborous

Did you try this tip?

你试过这个技巧吗?

Or better still, use ipython, and call:

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

then you can just use

debug_here()

whenever you want to set a breakpoint

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

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

那么你可以使用

debug_here()

每当你想设置断点

回答by TurinTurambar

If you type exit() in embed() console the code continue and go to the next embed() line.

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

回答by user6715080

The PyzoIDE has similar capabilities as the OP asked for. You don't have to start in debug mode. Similarly to MATLAB, the commands are executed in the shell. When you set up a break-point in some source code line, the IDE stops the execution there and you can debug and issue regular IPython commands as well.

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

It does seem however that step-into doesn't (yet?) work well (i.e. stopping in one line and then stepping into another function) unless you set up another break-point.

然而,除非您设置另一个断点,否则 step-into 似乎(还?)效果不佳(即停在一行中,然后进入另一个函数)。

Still, coming from MATLAB, this seems the best solution I've found.

尽管如此,来自 MATLAB,这似乎是我找到的最佳解决方案。

回答by Elliot Larson

Looks like the approach in @gaborous's answer is deprecated.

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

The new approach seems to be:

新方法似乎是:

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

def buggy_method():
    debug()