问题:使用IPython进行分步调试
根据我的阅读,有两种方法可以在Python中调试代码:
使用传统的调试器,例如
pdb
或ipdb
。它支持诸如c
forcontinue
,n
forstep-over
,s
forstep-into
等命令,但是您没有直接访问IPython shell的权限,这对于对象检查非常有用。通过将 IPython shell 嵌入代码中来使用 IPython。您可以这样做,然后在您的代码中使用。当您的程序/脚本命中一条语句时,您将进入IPython shell。这允许使用所有IPython好东西对对象进行全面检查并测试Python代码。但是,在使用时,您将无法通过便捷的键盘快捷键逐步完成代码。
from ipython import embed
embed()
embed()
embed()
有什么办法可以融合两全其美?即
- 能够 使用方便的pdb / ipdb键盘快捷键逐步完成代码。
- 在任何这样的步骤(例如,在给定的语句上),都可以访问成熟的IPython shell。
如在 MATLAB中一样进行 IPython调试:
在MATLAB中可以找到这种“增强调试”类型的示例,在该示例中,用户始终可以完全访问MATLAB引擎/外壳,并且她仍然可以逐步完成代码,定义条件断点等。我已经与其他用户讨论过,这是人们从MATLAB转移到IPython时最想念的调试功能。
在Emacs和其他编辑器中进行IPython调试:
我不想让这个问题过于具体,但是我主要在Emacs中工作,所以我想知道是否有任何方法可以将此功能引入其中。理想情况下,Emacs(或编辑器)将允许程序员在代码上的任意位置设置断点,并与解释器或调试器进行通信,以使其在您选择的位置停止,并在该位置提供完整的IPython解释器。
回答 0
您可以使用IPython的%pdb
IPython,当发生错误时,您会自动转到ipdb
。虽然您没有立即迈出一步,但您ipdb
之后就进入了。
这使调试单个函数变得容易,因为您可以使用加载文件%load
然后运行一个函数。您可以assert
在正确的位置使用来强制执行错误。
%pdb
是线魔术。呼之为%pdb on
,%pdb 1
,%pdb off
或%pdb 0
。如果在不带参数的情况下调用它,则它将作为切换。
回答 1
ipdb.set_trace()呢?在您的代码中:
import ipdb; ipdb.set_trace()
更新:现在在Python 3.7中,我们可以编写breakpoint()
。它的工作原理相同,但也遵守PYTHONBREAKPOINT
环境变量。此功能来自此PEP。
这样可以对代码进行全面检查,并且您可以访问诸如c
(继续),n
(执行下一行),s
(进入当前方法)之类的命令。
请参阅ipdb repo和命令列表。IPython现在称为Jupyter(的一部分)。
ps:请注意,ipdb命令优先于python代码。所以为了写,list(foo)
你需要print list(foo)
。
另外,如果您喜欢ipython提示符(它的emacs和vim模式,历史记录,完成情况等),由于它基于python提示符工具包,因此很容易为您的项目获得相同的名称。
回答 2
(2016年5月28日更新)在Emacs中使用RealGUD
对于Emacs中的任何人,此线程都说明了如何使用
- Emacs中一个称为RealGUD的新的重要调试器,可以与任何调试器(包括
ipdb
)一起使用。 - Emacs软件包
isend-mode
。
这两个软件包的组合非常强大,可以使它们完全重新创建OP中描述的行为,甚至可以做更多的事情。
有关RealGUD for ipdb 的Wiki文章的更多信息。
原始答案:
在尝试了多种不同的调试Python方法(包括本线程中提到的所有内容)之后,我使用IPython调试Python的首选方法之一是使用嵌入式外壳程序。
定义定制的嵌入式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
(2
)的值,查看定义了哪些函数和对象,等等。
问题:
上面的解决方案可以使Python在代码中所需的任何位置停止,然后将您带入完整的IPython解释器。不幸的是,调用脚本后,它不允许您添加或删除断点,这非常令人沮丧。在我看来,这是阻止IPython成为Python出色的调试工具的唯一原因。
您目前可以做的最好的事情是:
一种解决方法是ipsh()
在要Python解释程序启动IPython Shell的不同位置(即breakpoint
)放置先验先验。然后,您可以使用以下命令在不同的预定义,硬编码的“断点”之间“跳转”Ctrl-D
,这将退出当前的嵌入式IPython shell,并且每当解释器单击下一个调用时再次停止ipsh()
。
如果走这条路线,退出“调试模式”并忽略所有后续断点的一种方法是使用ipshell.dummy_mode = True
,这将使Python忽略ipshell
我们在上面创建的对象的任何后续实例化。
回答 3
您可以从pudb启动IPython会话,然后根据需要返回调试会话。
顺便说一句,ipdb在幕后使用IPython,您实际上可以使用IPython功能,例如TAB完成和魔术命令(以开头的命令%
)。如果你是IPDB OK,你可以从IPython中使用命令,如启动%run
和%debug
。从某种意义上讲,ipdb会话实际上比普通的IPython会话要好,因为您可以在堆栈跟踪中上下移动。ipdb中“对象检查”缺少什么?
另外,与Emacs> = 24.3捆绑在一起的python.el具有不错的ipdb支持。
回答 4
似乎@gaborous的答案中的方法已被弃用。
新方法似乎是:
from IPython.core import debugger
debug = debugger.Pdb().set_trace
def buggy_method():
debug()
回答 5
前缀“!” 在pdb中键入命令的符号似乎与在IPython shell中执行操作具有相同的效果。这适用于访问某些功能甚至变量名的帮助。也许这会对您有所帮助。例如,
ipdb> help(numpy.transpose)
*** No help on (numpy.transpose)
但是!help(numpy.transpose)将为您提供有关numpy.transpose的预期帮助页面。同样,对于变量名,假设您有一个变量l,在pdb中键入“ l”会列出代码,但是!l会打印出l的值。
回答 6
您是否尝试过此技巧?
或者更好的是,使用ipython并调用:
from IPython.Debugger import Tracer; debug_here = Tracer()
那你就可以用
debug_here()
每当你想设置一个断点
回答 7
您可以IPython
从内部 开始ipdb
!
引入ipdb
调试器1:
import idpb; ipdb.set_trace()
输入IPython的从内部在ipdb>
控制台2:
from IPython import embed; embed()
ipdb>
从以下位置返回到控制台IPython
:
exit
如果您有幸使用Emacs,可以使事情变得更加便捷!
这需要使用M-x shell
。使用yasnippet
和bm,定义以下代码段。这将用行替换ipdb
编辑器中的文本set-trace
。插入代码段后,该行将突出显示,以便易于观察和导航。使用M-x bm-next
导航。
# -*- mode: snippet -*-
# name: ipdb
# key: ipdb
# expand-env: ((yas-after-exit-snippet-hook #'bm-toggle))
# --
import ipdb; ipdb.set_trace()
1全部一行,易于删除。由于imports
仅发生一次,因此此表单确保ipdb
将在您需要时将其导入,而不会产生额外的开销。
2,您可以通过导入自己节省一些打字IPython
的内.pdbrc
文件:
try:
from IPython import embed
except:
pass
这使您可以简单地embed()
从内部进行调用ipdb
(当然,仅在安装IPython时)。
回答 8
一种选择是使用像Spyder这样的IDE ,它应该允许您在调试时与代码进行交互(实际上是使用IPython控制台)。实际上,Spyder非常类似于MATLAB,我认为这是故意的。其中包括变量检查器,变量编辑,对文档的内置访问等。
回答 9
该问题的正确,简单,酷爽的准确答案是将%run宏与-d标志一起使用。
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
回答 10
如果在embed()控制台中键入exit(),代码将继续并转到下一个embed()行。
回答 11
该Pyzo IDE具有与OP问类似的功能。您不必以调试模式启动。与MATLAB相似,命令在shell中执行。在某些源代码行中设置断点时,IDE会在此处停止执行,并且您还可以调试和发出常规IPython命令。
但是,除非您设置了另一个断点,否则似乎单步执行(还好吗?)效果不佳(即在一行中停下来,然后步入另一功能)。
仍然来自MATLAB,这似乎是我找到的最佳解决方案。
回答 12
在python 3.2中,您具有interact
命令,该命令可让您访问完整的python / ipython命令空间。
回答 13
从Emacs的IPython-shell和通过pdb.set_trace()设置的断点运行应该可以。
与python-mode.el,Mx ipython RET等一起检查
回答 14
开发新代码
在IPython中进行调试
- 使用Jupyter / IPython单元执行来加速实验迭代
- 使用%% debug逐步
单元格示例:
%%debug
...: for n in range(4):
...: n>2
调试现有代码
IPython内部调试
- 调试损坏的单元测试:
pytest ... --pdbcls=IPython.terminal.debugger:TerminalPdb --pdb
- 调试测试箱子外面:
breakpoint()
,python -m ipdb
,等。 - IPython.embed()用于在调试器中需要时具有完整的IPython功能
关于Python的想法
我同意OP的观点,MATLAB可以很好地完成许多事情,Python仍然没有,而且确实应该这样做,因为该语言中的几乎所有内容都偏重于开发速度而不是生产速度。也许有一天,我将为CPython贡献一些琐碎的错误修复。
https://github.com/ipython/ipython/commit/f042f3fea7560afcb518a1940daa46a72fbcfa68