如何在Python中使用Spyder进行高效的调试?

85

我喜欢Python,也喜欢Spyder,但是我认为使用Spyder进行调试太糟糕了!

  • 每次我设置断点,都需要按两个按钮:首先是调试按钮,然后是继续按钮(它自动暂停在第一行),这很烦人。
  • 此外,与其拥有具有自动完成等功能的标准iPython控制台,我却只有一个差劲的ipdb>>控制台,简直是垃圾。
  • 最糟糕的是,即使我编写打印或简单评估来尝试找出错误,这个控制台也经常会冻结。这比MATLAB还要糟糕。
  • 最后但并非最不重要的是,如果我从ipdb>>控制台中调用一个函数,并在其中设置断点,它将不会在那里停止。似乎我必须在开始调试之前在那里设置断点(Ctrl+F5)。

你有解决方案吗?或者你可以告诉我如何调试Python脚本和函数吗?

我正在使用Windows 8.1 64位上的全新安装Anaconda。


与复杂的调试无关,但我经常需要在脚本中间停止并在控制台中使用特定的变量进行进一步开发。我通常只是暂时地放置 sys.exit(),但如果有断点选项会更方便。 - wick
6个回答

61

(Spyder的维护者在这里) 在我们发布于2020年11月的4.2.0版本之后,Spyder中的调试体验非常好。现在我们提供的是Matlab用户会期望的调试器功能,即像IPython一样工作,并允许您在当前断点或帧中检查和绘制变量。

现在谈谈你提到的几个问题:

  1. 如果文件中有断点,则Spyder会进入调试模式并继续执行,直到遇到第一个断点。如果断点存在于另一个文件中,则仍然需要先按下Debug,然后按下Continue

  2. IPdb是IPython调试器控制台。在Spyder 4.2.0或更高版本中,它具有代码完成、语法突出显示、使用上/下箭头浏览命令历史记录(与IPython历史记录分开)、多行代码评估,以及使用Matplotlib进行内联和交互式绘图。

  3. 这个问题已经解决了。此外,为了避免Python代码和Pdb命令之间的冲突,如果您有一个名为n的变量并在提示符中写入n以查看其值,则我们将显示它而不是运行n Pdb命令。要运行该命令,您必须在前面加上感叹号,如此:!n

  4. 这个问题也已经解决了。您可以在IPdb中设置断点,并且它们将在当前会话中得到考虑。


15
我想指出另一个我认为很重要的功能。目前,只能通过“调试文件”来进行调试,在单独的会话中从头到尾运行文件,并忘记我在控制台中定义的所有变量。如果能够在传递已经定义在我的工作区中的变量时启动特定函数的调试,那将是很棒的(有时候重新计算这些变量是很费时的)。 - Leo
1
@neuronet,那已经可以工作了,但只有在按下调试按钮(即蓝色播放/暂停按钮)时才能工作。 - Carlos Cordoba
2
@neuronet,请在GitHub上开一个问题,以更好地了解您的情况发生了什么。 - Carlos Cordoba
2
@CarlosCordoba 好的,我会尽力不做任何愚蠢的事情。 :) - eric
1
@CarlosCordoba 我想我差不多搞定了。我必须确保整个文件没有任何错误,并点击播放/暂停按钮(因为像ctrl-F12这样的东西在我使用ctrl-F5进入调试模式之前什么也没做)。现在我看到了这一点,我可以更深入地探索它,但也更好地欣赏了OP和你的答案。Matlab在这方面真的很好,需要我适应...一些清晰的文档也会对此有所帮助,特别是对于期望Spyder“像Matlab一样”的Matlab用户的恢复。 - eric
显示剩余9条评论

35

调试工作流程

你需要明白实际上你正在使用不同的Python调试器pdbipdb(它使用pdb,可以通过模块ipdb访问)。我希望这个简单的例子能够帮助你更好地使用它。

假设你想要调试这段代码:

def Waiting_fun():                      #1 line number one
    for i in range(100):                #2
        pass                            #3
                                        #4 
def New_sum(lista, to_s = False):       #5
    result = 0                          #6
    print 1                             #7
    for i in lista:                     #8
        print "summed"                  #9   
        result +=i                      #10
    Waiting_fun()                       #11
    if to_s:                            #12
        result = str(result)
    return result
a = New_sum([1,4,5,7,8])
b = New_sum([1,4],1)
c = 456
d = New_sum([6,8,9],1)
final_result = a*b*c*d
Out: Type error

使用iPython %debug 进行快速首次调试

%debug

我首先要做的是使用魔术命令%debug从iPython中调用pdb,您可以使用%pdb将其设置为默认机制。

%debug
> /home/opdate/Desktop/test.py(23)<module>()
     19 a = New_sum([1,4,5,7,8])
     20 b = New_sum([1,4],1)
     21 c = 456
     22 d = New_sum([6,8,9],1)
---> 23 final_result = a*b*c*d

一旦你使用了 pdb,你可以在 官方文档 中找到所有命令,或者使用命令 h 来显示它们。在这个阶段,我只使用以下命令:
  • p:打印指定的变量
  • pp:漂亮的打印
  • args:如果你在函数内部,它会打印出参数
  • pp locals():打印所有变量可能很有用,但大多数情况下会很混乱!
  • !:如果你想避免与 h 列出的命令冲突,可以使用它
  • whatis 变量名:相当于 type(variable_name)
  • u:将当前帧向上移动一个堆栈跟踪级别(到较旧的帧)。
  • d:将当前帧向下移动一个堆栈跟踪级别(到较新的帧)。
  • q:完成后,可以使用 q 退出

在我们的例子中:

ipdb> pp a,b,c,d
(25, '5', 456, '23')

或者 ipdb>!a,b,c,d(感叹号和第一个值之间没有空格)。 很明显,如果我们可以使用,b和d是字符串:

ipdb> whatis b
<type 'str'>

使用断点深入了解

70%的时间%debug会指向解决方案。当您需要更多功能,如断点时,就是使用Spyder的时候了。在这种情况下,我们想要了解为什么b是一个字符串,我们在其旁边设置一个断点(在编辑器窗口中双击行号旁边)。我发现使用标准的Python控制台而不是IPython控制台进行调试要好得多,因此在开始调试之前选择控制台: enter image description here

然后打开变量资源管理器,如果有任何变量,请将其删除。我使用Ctrl+F5来开始调试,您可以使用顶部的按钮,但我更喜欢使用下面显示的快捷键:

enter image description here

(Pdb) c # we go to the breakpoint 
(Pdb) s # we step into the function
(Pdb) args # we see what parameters are inserted
(Pdb) s # going step-by-step
(Pdb) ⏎ # series of Enters go line by line quicker
#Here I'll use  whatis command but in fact I just look to
# the type in variable explorer of spyder.
(Pdb) whatis result #check if result is still int
(Pdb) unt #or until -useful to exiting from loops see doc.
(Pdb) n # we  don't  enter to the Waiting_fun function
(Pdb) s # going step-by-step
(Pdb) whatis result #we find that there the int is converted
(Pdb) j 6 # for double checking we jump back to 6 were the result is assigned 
# We may be tempted to j(ump) to line 12 but doing so we would skip all the code
#for avoiding a series of `s`,`unt` and `n` we can use this solution:
(Pdb) tbreak 12 #set a new temporary breakpoint. Also `b` it's ok most of the time
(Pdb) c  # go to it 
(Pdb) j 6 # we jump to 6 the code we jump is NOT executed
(Pdb) whatis result# we find that if we jump 12-13 result is still int

现在我们已经找到了错误。我们也可以测试一个解决方案,重复步骤直到12并将to_s = False设置。
(Pdb) to_s = False #!to_s = False to be on the safe side

它有效。在Python控制台中使用标准pdb的一个重要特性是,您可以自动补全并使用变量资源管理器,而不是使用whatispp

enter image description here

使用变量资源管理器,您还可以更快地更改变量的值,从而更快地定位错误。

条件断点

另一种更聪明的定位错误的方法是使用条件断点Shift+F12)。Spyder的一个很大优势是进行调试并使用列表断点。当条件为True时,将激活条件断点。在我们的例子中,我们想要定位b何时变成字符串,因此条件是:type(b) == str。我通常会放置许多条件断点,并查看哪些满足条件。为此,请不要使用Shift+F12,而是双击行旁边放置普通断点,然后转到Debug->List breakpoints,并将条件复制并粘贴到每个断点的表中,如下图所示。

enter image description here

从这里开始,使用的命令如下:

(Pdb) c  # go to the first
(Pdb) u # it helps to understand when it happened
(Pdb) d # come back to the breakpoint

这是一些好的信息。不幸的是Spyder无法在我的断点处停止。我已经成功地在VSCode,PyCharm和PyScripter中使用了断点。我希望我能弄清楚我在Spyder中缺少什么……这并不明显。 - Wesley Kitlasten
谢谢@WesleyKitlasten,关于你的问题,你可能想考虑在Spyder Github存储库中打开一个问题,对我来说它运行良好。 - G M

4

pdb调试器在普通的python中可以正常工作。因此,在Spyder中,每当我想进行交互式调试时,我只需要切换到python控制台即可。

import pdb

def yourfunction():
    # Interesting stuff done here
    pdb.set_trace() 

很好的介绍了使用pdb进行调试。链接如下:https://pythonconquerstheuniverse.wordpress.com/category/python-debugger/

1
很遗憾:注意:Python控制台将在Spyder 3.2中被删除。请开始将您的工作迁移到IPython控制台。 - C8H10N4O2

1

显然以前没有人提到过这两个:

在使用Python之前,我使用的是VBA。虽然它是一种相对较旧的语言,不经常更新,但我喜欢VBA的一个功能是调试函数。与VBA最接近或也可以称为“可视化调试”的2个调试函数是:

1-PyCharm调试器

6分钟视频演示了PyCharm调试器。

2-PixieDebugger - Jupyter Notebook的可视化Python调试器

由于许多编码人员倾向于使用JupyterNotebook,因此这个调试器将会很方便。 PixieDebugger几乎与PyCharm调试器相同。我不会在这里详细介绍。

但您可以参考此链接


2
这个问题是关于Spyder的,你提到的任何调试器都不能在Spyder中使用。 - Carlos Cordoba
1
我知道这一点。我只是强调不同类型的Python可视化调试器,不一定是针对Spyder的。 - mcagriardic

1

以下是我在Spyder中进行调试的方法,以避免冻结IDE。如果我在调试模式下更改脚本,我会这样做。

  1. 关闭当前的IPython(调试)控制台[x]
  2. 打开一个新的控制台[菜单栏->控制台->打开IPython控制台]
  3. 再次进入调试模式[蓝色播放暂停按钮]。

虽然有点烦人,但它具有清除(重置)变量列表的附加好处。


0
你可以使用调试快捷键,例如: 跳过 F10 步入 F11 在工具>首选项>键盘快捷方式中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接