(2016 年 5 月 28 日更新)在 Emacs 中使用 RealGUD
对于 Emacs 中的任何人,此线程显示了如何使用 OP(以及更多)完成所有描述
- Emacs 中一个新的重要调试器,称为RealGUD,它可以与任何调试器(包括
ipdb
)一起运行。
- Emacs 包
isend-mode
。
这两个包的组合是非常强大的,它允许一个人准确地重新创建 OP 中描述的行为并做更多的事情。
有关RealGUD for ipdb的 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)
以下列方式之一调用:
- 通过运行从 Unix shell 调用此函数的 Python 程序
- 或者直接从 IPython 调用它
不管我如何调用它,解释器都会停在ipsh()
. 完成后,您可以执行此操作Ctrl-D
,Python 将继续执行(使用您所做的任何变量更新)。请注意,如果您从常规 IPython 和 IPython shell(上面的案例 2)运行代码,新的 IPython shell 将嵌套在您调用它的那个中,这非常好,但最好注意一下。不管怎样,一旦解释器停在 的位置ipsh
,我就可以检查a
(which be 2
) 的值,查看定义了哪些函数和对象等。
问题:
上面的解决方案可用于让 Python 在代码中的任何位置停止,然后将您放入成熟的 IPython 解释器。不幸的是,一旦调用脚本,它就不允许您添加或删除断点,这非常令人沮丧。在我看来,这是阻止 IPython 成为 Python 的出色调试工具的唯一原因。
你现在能做的最好的事情:
一种解决方法是将ipsh()
先验放置在您希望 Python 解释器启动 IPython shell(即 a breakpoint
)的不同位置。然后,您可以在不同的预定义、硬编码的“断点”之间“跳转” Ctrl-D
,这将退出当前嵌入式 IPython shell,并在解释器下一次调用ipsh()
.
如果你走这条路,退出“调试模式”并忽略所有后续断点的一种方法是使用ipshell.dummy_mode = True
这将使 Python 忽略ipshell
我们在上面创建的对象的任何后续实例化。