调试工作流程
你需要明白实际上你正在使用不同的Python调试器pdb
和ipdb
(它使用pdb
,可以通过模块ipdb
访问)。我希望这个简单的例子能够帮助你更好地使用它。
假设你想要调试这段代码:
def Waiting_fun():
for i in range(100):
pass
def New_sum(lista, to_s = False):
result = 0
print 1
for i in lista:
print "summed"
result +=i
Waiting_fun()
if to_s:
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](https://istack.dev59.com/yDvfP.webp)
然后打开变量资源管理器
,如果有任何变量,请将其删除。我使用Ctrl+F5来开始调试,您可以使用顶部的按钮,但我更喜欢使用下面显示的快捷键:
![enter image description here](https://istack.dev59.com/CwQAF.webp)
(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
它有效。在Python控制台中使用标准pdb的一个重要特性是,您可以自动补全并使用变量资源管理器,而不是使用whatis
和pp
:
![enter image description here](https://istack.dev59.com/0IVHU.webp)
使用变量资源管理器,您还可以更快地更改变量的值,从而更快地定位错误。
条件断点
另一种更聪明的定位错误的方法是使用
条件断点(
Shift+
F12)。Spyder的一个很大优势是进行调试并使用列表断点。当条件为
True
时,将激活条件断点。在我们的例子中,我们想要定位b何时变成字符串,因此条件是:
type(b) == str
。我通常会放置许多条件断点,并查看哪些满足条件。为此,请不要使用
Shift+
F12,而是双击行旁边放置普通断点,然后转到Debug->List breakpoints,并将条件复制并粘贴到每个断点的表中,如下图所示。
![enter image description here](https://istack.dev59.com/gLIeA.webp)
从这里开始,使用的命令如下:
(Pdb) c
(Pdb) u
(Pdb) d
sys.exit()
,但如果有断点选项会更方便。 - wick