用IPython逐步debugging
从我读到的,有两种方法来在Python中debugging代码:
-
使用传统的debugging器,如
pdb
或ipdb
。 这支持命令,例如c
continue
,n
为step-over
,s
为step-into
等等),但是你不能直接访问IPython shell,这对于对象检查是非常有用的。 -
通过在代码中embedded IPython shell来使用IPython 。 你可以
from ipython import embed
来做,然后在你的代码中使用embed()
。 当你的程序/脚本碰到一个embed()
语句时,你被放到一个IPython shell中。 这允许使用所有IPython的好东西全面检查对象并testingPython代码。 但是,在使用embed()
您不能一步一步地通过代码来使用方便的键盘快捷键。
有什么办法可以把两全其美? 即
- 使用方便的pdb / ipdb键盘快捷键,可以一步一步通过代码。
- 在任何这样的步骤(例如,在一个给定的语句),可以访问一个完整的IPython shell 。
在 MATLAB中进行IPythondebugging:
在MATLAB中可以find这种types的“增强型debugging”的例子,在那里用户总是可以完全访问MATLAB引擎/ shell,她仍然可以一步一步地通过她的代码,定义条件断点等。我已经和其他用户讨论过,这是人们从MATLAB转移到IPython时错过最多的debuggingfunction。
在Emacs和其他编辑器中进行IPythondebugging:
我不想让这个问题太具体,但我主要在Emacs工作,所以我想知道是否有任何方法将这个function。 理想情况下 ,Emacs(或编辑器)将允许程序员在代码的任何位置设置断点,并与解释器或debugging器进行通信,使其停止在您select的位置,并在该位置带上一个完整的IPython解释器。
怎么样ipdb.set_trace()? 在你的代码中:
import ipdb; ipdb.set_trace()
这允许对代码进行全面检查,并且可以访问c
(continue), n
(执行下一行), s
(进入方法)等命令。
请参阅ipdb repo和命令列表 。 IPython现在被称为(编辑: Jupyter的一部分)。
ps:请注意,ipdb命令优先于Python代码。 所以为了写list(foo)
你需要print list(foo)
。
另外,如果你喜欢ipython的提示符(它的emacs和vim模式,历史,完成,…),它很容易让你的项目相同,因为它是基于python提示工具包 。
(2016年5月28日更新)在Emacs中使用RealGUD
对于Emacs中的任何人来说, 这个线程展示了如何使用OP(以及更多)完成描述的所有内容
- Emacs中一个新的重要的debugging器叫做RealGUD ,可以和任何debugging器(包括
ipdb
)一起工作。 - Emacs包
isend-mode
。
这两个软件包的结合是非常强大的,可以让用户准确地重新创buildOP中描述的行为,甚至可以做到更多。
关于ipdb的RealGUD wiki文章的更多信息。
原始答案:
在尝试了很多不同的方法来debuggingPython之后,包括在这个线程中提到的所有东西之后,用IPythondebuggingPython的首选方法之一就是embedded式shell。
定义一个定制的embedded式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)
然后,每当我想在我的代码中debugging某些东西时,我将ipsh()
放在需要进行对象检查的位置等等。例如,假设我想在下面debuggingmy_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将恢复执行(与您所做的任何variables更新)。 请注意,如果您从IPython IPython shell(上面的第2种情况)运行代码,则新的IPython shell将嵌套在您调用它的那个内部,这非常好,但是很好理解。 无论如何,一旦解释器停在ipsh
的位置,我可以检查a
(它是2
)的值,看看定义了什么函数和对象等等。
问题:
上面的解决scheme可以用来让Python在代码中的任何地方停下来,然后把你放到一个完整的IPython解释器中。 不幸的是,一旦你调用脚本,它不会让你添加或删除断点,这是非常令人沮丧的。 在我看来,这是阻止IPython成为Python的一个很好的debugging工具的唯一的东西。
你现在可以做的最好的:
解决方法是将ipsh()
事先放在希望Python解释器启动IPython shell(即breakpoint
)的不同位置。 然后,您可以用Ctrl-D
在不同的预定义的硬编码的“断点”之间“跳转”,这会退出当前embedded的IPython shell,并在解释器遇到下一次调用ipsh()
时再次停止。
如果走这条路线,一种退出“debugging模式”并忽略所有后续断点的方法是使用ipshell.dummy_mode = True
,这将使Python忽略上面创build的ipshell
对象的任何后续实例化。
您可以从pudb启动IPython会话,然后根据需要返回到debugging会话。
顺便说一下,ipdb在后台使用IPython,你可以实际使用IPython的function,如TAB完成和魔术命令(以%
开头)。 如果您使用ipdb可以,您可以使用命令(如%run
和%debug
从IPython启动它。 ipdb会话实际上比普通IPython更好,您可以在堆栈跟踪等中进行上下传递。ipdb中缺less“对象检查”function吗?
另外,与Emacs> = 24.3捆绑在一起的python.el具有良好的ipdb支持。
前缀“!” 符号到在pdb中input的命令似乎与在IPython shell中执行某些操作具有相同的效果。 这适用于访问某个函数的帮助,甚至是variables名称。 也许这会在一定程度上帮助你。 例如,
ipdb> help(numpy.transpose) *** No help on (numpy.transpose)
但!help(numpy.transpose)会给你numpy.transpose预期的帮助页面。 同样,对于variables名称,假设你有一个variablesl,在pdb中键入“l”列出了代码,但是!l打印出l的值。
看起来像@ gaborous的答案中的方法已被弃用 。
新方法似乎是:
from IPython.core import debugger debug = debugger.Pdb().set_trace def buggy_method(): debug()
没有人提到IPython的%pdb
标志呢。 只需在IPython中调用%pdb
,并在发生错误时自动将其删除到ipdb
。 虽然你没有立即步进,你以后在ipdb
。
这使得debugging单个函数变得简单,因为你可以只加载一个带有%load
的文件,然后运行一个函数。 你可以在正确的位置assert
一个错误。
你试过这个提示吗?
或者更好的是,使用ipython,然后调用:
from IPython.Debugger import Tracer; debug_here = Tracer()
那么你可以使用
debug_here()
每当你想设置一个断点
一种select是使用像Spyder这样的IDE,它允许你在debugging的时候和你的代码进行交互(事实上使用IPython控制台)。 事实上,Spyder是非常类似于MATLAB的,我认为这是有意的。 这包括variables检查器,可变编辑,内置的文档访问等。
如果在embed()控制台中inputexit(),则代码继续并转到下一个embed()行。
Pyzo IDE与OP要求的function类似。 您不必以debugging模式启动。 类似于MATLAB,这些命令在shell中执行。 在某些源代码行中设置断点时,IDE会停止执行,您也可以debugging并发出常规的IPython命令。
然而,看起来步入式还没有(还没有)工作得很好(即停在一条线上,然后进入另一个function),除非你设置了另一个断点。
不过,来自MATLAB,这似乎是我find的最好的解决scheme。
从Emacs的IPython-shell和通过pdb.set_trace()设置的断点运行应该工作。
用python-mode.el,Mx,ipython等检查