简体   繁体   English

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

[英]How do I debug efficiently with Spyder in Python?

I like Python and I like Spyder but I find debugging with Spyder terrible!我喜欢 Python 和 Spyder,但我发现使用 Spyder 进行调试很糟糕!

  • Every time I put a break point, I need to press two buttons: first the debug and then the continue button (it pauses at first line automatically) which is annoying.每次设置断点时,我都需要按两个按钮:首先是调试按钮,然后是继续按钮(它会自动在第一行暂停),这很烦人。
  • Moreover, rather than having the standard iPython console with auto completion etc I have a lousy ipdb>> console which is just garbage.此外,我有一个糟糕的 ipdb>> 控制台,而不是具有自动完成功能等的标准 iPython 控制台,它只是垃圾。
  • The worst thing is that this console freezes very frequently even if I write prints or simple evaluation to try to figure out what is the bug.最糟糕的是,即使我写了一些打印或简单的评估来试图找出错误所在,该控制台也会非常频繁地冻结。 This is much worse than MATLAB.这比MATLAB差很多。
  • Last but not least, if I call a function from within the ipdb>> console, and put a breakpoint in it, it will not stop there.最后但并非最不重要的是,如果我从 ipdb>> 控制台中调用一个函数,并在其中放置一个断点,它不会停在那里。 It seems like I have to put the breakpoint there before I start the debugging ( Ctrl+F5 ).似乎我必须在开始调试之前将断点放在那里( Ctrl+F5 )。

Do you have a solution or maybe can you tell me how you debug Python scripts and functions?你有解决方案吗,或者你能告诉我你是如何调试 Python 脚本和函数的吗?

I am using fresh install of Anaconda on a Windows 8.1 64bit.我在 Windows 8.1 64 位上使用全新安装的 Anaconda。

( Spyder maintainer here ) After our 4.2.0 version, released in November 2020, the debugging experience in Spyder is quite good. 这里是Spyder维护者)我们2020年11月发布4.2.0版本后,Spyder的调试体验相当不错。 What we provide now is what people coming from Matlab would expect from a debugger, ie something that works like IPython and lets you inspect and plot variables at the current breakpoint or frame.我们现在提供的是来自 Matlab 的人们对调试器的期望,即像 IPython 一样工作的东西,可以让您在当前断点或帧处检查和绘制变量。

Now about your points:现在谈谈你的观点:

  1. If there is a breakpoint present in the file you're trying to debug, then Spyder enters in debug mode and continues until the first breakpoint is met.如果您尝试调试的文件中存在断点,则 Spyder 进入调试模式并继续运行,直到遇到第一个断点。 If it's present in another file, then you still need to press first Debug and then Continue .如果它存在于另一个文件中,那么您仍然需要先按Debug ,然后再按Continue

  2. IPdb is the IPython debugger console. IPdb是 IPython 调试器控制台。 In Spyder 4.2.0 or above it comes with code completion, syntax highlighting, history browsing of commands with the up/down arrows (separate from the IPython history), multi-line evaluation of code, and inline and interactive plots with Matplotlib.在 Spyder 4.2.0 或更高版本中,它带有代码完成、语法突出显示、使用向上/向下箭头(与 IPython 历史分开)的命令历史浏览、代码的多行评估以及与 Matplotlib 的内联和交互式绘图。

  3. This is fixed now.现在已修复。 Also, to avoid clashes between Python code and Pdb commands, if you have (for instance) a variable called n and write n in the prompt to see its value, we will show it instead of running the n Pdb command.此外,为了避免 Python 代码和 Pdb 命令之间的冲突,如果您有(例如)一个名为n的变量并在提示中写入n以查看其值,我们将显示它而不是运行n Pdb 命令。 To run that command instead, you have to prefix it with an exclamation mark, like this: !n要运行该命令,您必须在它前面加上一个感叹号,如下所示: !n

  4. This is fixed too.这也是固定的。 You can set breakpoints in IPdb and they will be taken into account in your current session.您可以在IPdb设置断点,它们将在您当前的会话中被考虑在内。

Debugging workflow调试工作流

You have to understand that in fact you are using different integration of the Python debugger pdb and ipdb (which uses pdb and which can be accessed using the module ipdb ).您必须了解,实际上您使用的是Python 调试器pdbipdb (使用pdb并且可以使用模块ipdb访问)的不同集成。 I hope this trivial example will help you with using it better.我希望这个简单的例子能帮助你更好地使用它。

Suppose you want to debug this code:假设您要调试此代码:

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

Quick first debugging using iPython %debug使用 iPython 进行快速第一次调试 %debug

%debug

The first thing I do is to call pdb from iPython using the magic command %debug , you can set it as a default mechanism using %pdb .我做的第一件事是使用魔术命令%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

Once you have lunch pdb .一旦你吃过午饭pdb You can find all command in the official docs or you can use the command h to display them.您可以在官方文档中找到所有命令,也可以使用命令h来显示它们。 In this stage the only commands that I use are:在这个阶段,我使用的唯一命令是:

  • p : prints the variables that you specify p :打印您指定的变量
  • pp : pretty prints pp : 漂亮的印刷品
  • args : if you are inside a function it prints the arguments args : 如果你在一个函数里面,它会打印参数
  • pp locals() : can be useful to print all the variables but most of the times it is a mess! pp locals() :打印所有变量很有用,但大多数时候它是一团糟!
  • ! use it if you want to avoid conflicts with the commands listed in h如果您想避免与h列出的命令发生冲突,请使用它
  • whatis variable_name: equivalent of type(variable_name) whatis variable_name:相当于类型(variable_name)
  • u : Move the current frame one level up in the stack trace (to an older frame). u :将当前帧在堆栈跟踪中向上移动一级(到较旧的帧)。
  • d : Move the current frame one level down in the stack trace (to a newer frame). d :将当前帧在堆栈跟踪中向下移动一级(到更新的帧)。
  • q : when you finish you can use q for quitting q : 完成后可以使用 q 退出

In our case:在我们的例子中:

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

Or ipdb> !a,b,c,d (no space between esclamation mark and first value).或者ipdb> !a,b,c,d (感叹号和第一个值之间没有空格)。 It's clear that b and d are strings in case we can use:很明显, b 和 d 是字符串,以防我们可以使用:

ipdb> whatis b
<type 'str'>

Going deeper using break-points使用断点更深入

70% of the times %debug points you to the solution. 70% 的情况下%debug指向解决方案。 When you need more features like breakpoints is time to use Spyder.当您需要更多像断点这样的功能时,是时候使用 Spyder 了。 In this case, we want to understand why b is a string we put a breakpoint next to it (double-clicking next to the line number in the editor window).在这种情况下,我们想了解为什么b是一个字符串,我们在它旁边放置了一个断点(在编辑器窗口中的行号旁边双击)。 I find much better to use the standard Python console instead of the IPython console for debugging so select the console before starting debugging:我发现使用标准 Python 控制台而不是 IPython 控制台进行调试要好得多,因此在开始调试之前选择控制台: 在此处输入图片说明

Then open the variable explorer if there are any variables delete them.然后打开variable explorer如果有任何变量删除它们。 I use Ctrl + F5 to start the debugging you can use the buttons on the top but I prefer to use their shortcuts shown below:我使用Ctrl + F5开始调试,您可以使用顶部的按钮,但我更喜欢使用如下所示的快捷方式:

在此处输入图片说明

(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

Now we have located the error.现在我们已经找到了错误。 We can also test a solution we repeat the step until 12 and we set to_s = False我们还可以测试一个解决方案,我们重复该步骤直到 12 并且我们设置为to_s = False

(Pdb) to_s = False #!to_s = False to be on the safe side

It works.有用。 One important feature using the standard pdb in the Python console , is that you have auto competition and you can use the variable explorer instead of using whatis and pp :Python 控制台中使用标准 pdb 的一项重要功能是,您可以进行自动竞争,并且可以使用变量资源管理器而不是使用whatispp

在此处输入图片说明

Using the variable explorer you can also change the value of the variables which makes the things even quicker.使用变量资源管理器,您还可以更改变量的值,从而使事情变得更快。

Conditional breakpoints条件断点

Another more clever way to locate the error is to use conditional breakpoint ( Shift + F12 ) a great advantage of Spyder is going to debug and use list breakpoints.定位错误的另一种更聪明的方法是使用条件断点Shift + F12 ) Spyder 的一大优势是调试和使用列表断点。 Conditional breakpoints are activated when the condition is True In our case, we want to locate where b becomes a string so the condition is: type(b) == str .当条件为True时激活条件断点在我们的例子中,我们想要定位 b 成为字符串的位置,因此条件是: type(b) == str I usually place a lot of conditional breakpoints and see which ones meet the condition.我通常会放置很多条件断点,看看哪些符合条件。 For doing so don't use Shift + F12 but place normal breakpoints double-clicking next to the line and go to Debug->List breakpoints and copy and past the condition in the table to every breakpoint as shown in the figure below.为此,不要使用Shift + F12,而是在该行旁边双击放置正常断点,然后转到 Debug->List breakpoints 并将表中的条件复制并粘贴到每个断点,如下图所示。

在此处输入图片说明

From here the commands to use are:从这里使用的命令是:

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

The pdb debugger works just fine with regular python . pdb 调试器与常规 python一起工作得很好。 So in Spyder, I just switch to the python console whenever I want to debug interactively.所以在 Spyder 中,每当我想交互式调试时,我就切换到 python 控制台。

import pdb

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

Nice intro to debugging with pdb https://pythonconquerstheuniverse.wordpress.com/category/python-debugger/使用 pdb 进行调试的不错介绍https://pythonconquerstheuniverse.wordpress.com/category/python-debugger/

Here is how I debug in Spyder in order to avoid freezing the IDE.这是我在 Spyder 中调试以避免冻结 IDE 的方法。 I do this if I alter the script while in debugging mode.如果我在调试模式下更改脚本,我会这样做。

  1. I close out the current IPython (debugging) console [x]我关闭了当前的 IPython(调试)控制台 [x]
  2. Open a new one [Menu bar-> Consoles-> Open an IPython Console]新建一个【菜单栏->控制台->打开一个IPython控制台】
  3. Enter debug mode again [blue play pause button].再次进入调试模式【蓝色播放暂停按钮】。

Still a bit annoying, but it has the added benefit of clearing (resetting) variable list.仍然有点烦人,但它具有清除(重置)变量列表的额外好处。

No one has ever mentioned about these two before apparently:显然之前没有人提到过这两个:

Before Python, I was using VBA.在 Python 之前,我使用的是 VBA。 Although it is a relatively old language that is not regularly updated, one thing I loved about VBA was the debugging function.虽然它是一种相对较旧的语言,不定期更新,但我喜欢 VBA 的一件事是调试功能。 The 2 debugging functions that are closest to VBA or which can also be termed as "visual debugging" I had come across are:我遇到的最接近 VBA 或也可以称为“可视化调试”的 2 个调试函数是:

1-PyCharm Debugger 1-PyCharm 调试器

This 6 minutes video demonstrates PyCharm debugger.这个6 分钟的视频演示了 PyCharm 调试器。

2-PixieDebugger - The Visual Python Debugger for Jupyter Notebooks You've Always Wanted 2-PixieDebugger - 您一直想要的 Jupyter Notebook 的可视化 Python 调试器

Since many coders tend to use JupyterNotebook, this debugger would come in handy.由于许多编码人员倾向于使用 JupyterNotebook,因此这个调试器会派上用场。 PixieDebugger is almost the same as PyCharm debugger. PixieDebugger 几乎与 PyCharm 调试器相同。 I will not go into detail in here.我不会在这里详细介绍。

But you can refer to this link但是你可以参考这个链接

One minor extra regarding point 3:关于第 3 点的一个小补充:

It also seemed to me the debug console frequently froze, doing prints, evaluating, etc, but pressing the stop (Exit debug) button usually got it back to the bottom of the call stack and then I could go back up ('u') to the frame I was debugging in. Worth a try.在我看来,调试控制台经常冻结,进行打印、评估等,但按停止(退出调试)按钮通常会使其回到调用堆栈的底部,然后我可以返回('u')到我正在调试的框架。值得一试。 This might be for a later version of Spyder (2.3.5.2)这可能适用于更高版本的 Spyder (2.3.5.2)

您可以使用调试快捷键,例如:在工具>首选项>键盘快捷键中步过 F10 步入 F11

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM