python高级调试技巧(一)——原生态的pdb调试
python进阶教程
机器学习
深度学习
长按二维码关注
进入正文
python高级调试技巧(一)——原生态的pdb调试
目录
一 使用系统自带的pdb模式模块进行单
步调试
二 使用set_trace()设置断点
三 pdb模块方法详解
四 使用ipython和jupyter notebook
进行调试(下篇预告)
声明:本文所讲的调试是指不附带任何工具的调试,我们平时使用vs code,pycharm进行调试,包括设置断点、单步执行、多步执行等操作都是IDE设置好的,本文不考虑这些,使用原生态的python调试器,不需要任何IDE开发环境。pdb是python自带的调试器,是python debugger 的简称。使用pdb调试有两种方式。
本次文章依然是分为系列文章进行讲解,本文为系列文章第一篇。
01
使用系统自带的pdb模式模块进行单
步调试
(Pdb),这就表示进入了pdb命令调试。然后输入下面的命令即可。
注意:我们经常看见在python代码中会有 import pdb 这样的语句,但是这样的“单步执行模式”,是不需要在代码里面添加这句话的,当然添加也可以。
pdb命令行:
1)进入命令行Debug模式,python -m pdb xxx.py 这个格式是固定的
之所以可以这样做,主要是因为pdb.py 可以被当做一个脚本script执行。
2)h:(help)帮助
3)w:(where)打印当前执行堆栈
4)d:(down)执行跳转到在当前堆栈的深一层(个人没觉得有什么用处)
5)u:(up)执行跳转到当前堆栈的上一层
6)b:(break)添加断点
b 列出当前所有断点,和断点执行到统计次数
b line_number:当前脚本的line_no行添加断点
b filename:line_number:脚本filename的line_no行添加断点
b function:在函数function的第一条可执行语句处添加断点
7)tbreak:(temporary break)临时断点
在第一次执行到这个断点之后,就自动删除这个断点,用法和b一样
8)cl:(clear)清除断点
cl 清除所有断点
cl bpnumber1 bpnumber2... 清除断点号为bpnumber1,bpnumber2...的断点
cl line_number 清除当前脚本line_number行的断点
cl filename:line_number 清除脚本filename的line_number行的断点
9)disable:停用断点,参数为bpnumber,和cl的区别是,断点依然存在,只是不启用
10)enable:激活断点,参数为bpnumber(即哪一个断点,1,2,3,4......)
11)s:(step)执行下一条命令
如果本句是函数调用,则s会执行到函数的第一句
12)n:(next)执行下一条语句
如果本句是函数调用,则执行函数,接着执行当前执行语句的下一条。
13)r:(return)执行当前运行函数到结束
14)c:(continue)继续执行,直到遇到下一条断点,这个比较重要,常常和断点结合起来使用。
15)l:(list)列出源码
l 列出当前执行语句周围11条代码
l first 列出first行周围11条代码
l first second 列出first--second范围的代码,如果second<first,second将被解析为行数
16)a:(args)列出当前执行函数的函数
17)p expression:(print)输出expression的值
比如:(Pdb) p 1+2
这里会打印出 3
再比如:(Pdb) p c #这里用来查看某个变量c的值
18)pp expression:好看一点的p expression
19)run:重新启动debug,相当于restart
20)q:(quit)退出debug
21)j lineno:(jump)设置下条执行的语句函数
只能在堆栈的最底层跳转,向后重新执行,向前可直接执行到行号
22)unt:(until)执行到下一行(跳出循环),或者当前堆栈结束
23)condition bpnumber conditon,给断点设置条件,当参数condition返回True的时候bpnumber断点有效,否则bpnumber断点无效
注意:
1:直接输入Enter,会执行上一条命令;
2:输入PDB不认识的命令,PDB会把他当做Python语句在当前环境下执行;
3:常用的命令有,(6)(8)(9)(10)(11)(12)(13)(14)(15)(16)(17)(18)(19)(20)
02
使用set_trace()设置断点
pdb单步执行太麻烦了,所以第二种方法是import pdb 之后,直接在代码里需要调试的地方放一个pdb.set_trace(),就可以设置一个断点, 程序会在pdb.set_trace()暂停并进入pdb调试环境,可以用pdb 变量名查看变量,或者c继续运行。
如下代码:
import pdb #导入这个模块
print('这是一个python调试程序')
def func1():
for i in range(5):
print(i)
def func2(a,b):
return a/b
if __name__=='__main__':
func1()
pdb.set_trace() #设置断点,程序会在调试的时候直接进入到这里暂停
result=func2(3,0)
print(result)
下面开始调试,
(base) C:\Users\lenovo>python F:\Python调试.py #执行脚本
这是一个python调试程序
0
1
2
3
4 #自动执行到断点处
> f:\研究生二年级下\c#再学习\python调试\python调试\python调试.py(14)<module>()
-> result=func2(3,0)
(Pdb) n
ZeroDivisionError: division by zero
> f:\研究生二年级下\c#再学习\python调试\python调试\python调试.py(14)<module>()
-> result=func2(3,0)
(Pdb) n
--Return--
> f:\研究生二年级下\c#再学习\python调试\python调试\python调试.py(14)<module>()->None
-> result=func2(3,0)
(Pdb) n
总结:
使用set_trace()设置断点之后,调用脚本的时候,不再需要 -m pdb 这一块了,直接调用,然后就会进入调试模式,
几面会出现(Pdb),然后相关的执行命令和前面的是一样的。
03
pdb模块详解
1、pdb.set_trace() 设置断点
2、pdb.run(statement[, globals[, locals]]) ——主要用来调试代码块
statement:需要进行调试的某一段代码,以字符串的形式给出
globals: 设置statement运行的全局环境变量
locals: 设置statement运行的局部环境变量
整体的作用类似于python内置模块的eval函数。
s='''a=100
b=20
c=0
d=a/b
e=d/c
'''
pdb.run(s)
现在运行上面这段代码,python Python调试.py
的搭配下面的结果:
(base) C:\Users\lenovo>python F:\研究生二年级下\C#再学习\Python调试\Python调试\Python调试.py
> <string>(1)<module>()
(Pdb) n
> <string>(2)<module>()
(Pdb) n
> <string>(3)<module>()
(Pdb) n
> <string>(4)<module>()
(Pdb) n
> <string>(5)<module>()
(Pdb) n
ZeroDivisionError: float division by zero
> <string>(5)<module>()
补充:
(1)globals:这个参数管控的是一个全局的命名空间,也就是我们在计算表达式的时候可以使用全局的命名空间中的函数,如果这个参数被提供了,并且没有提供自定义的__builtins__,那么会将当前环境中的__builtins__拷贝到自己提供的globals里,然后才会进行计算。关于__builtins__,它是python的内建模块,也就是python自带的模块,不需要我们import就可以使用的,例如我们平时使用的int、str、abs等都在这个模块中。关于它的说明可以参照这篇文章:点击打开链接。如果globals没有被提供,则使用python的全局命名空间。
(2)locals:这个参数管控的是一个局部的命名空间,和globals类似,不过当它和globals中有重复的部分时,locals里的定义会覆盖掉globals中的,也就是当globals和locals中有冲突的部分时,locals说了算,它有决定权,以它的为准。如果locals没有被 提供的话,则默认为globals。
3、pdb.runeval(expression,globals,locals)——主要用来调试表达式
expression也是以字符串的形式给出的,当表达式有返回值的时候,这个函数返回的值就是表达式所返回的值,如果没有返回值,那和上面的pdb.run()是一样的。
4、pdb.runcall(function[, argument, ...])——主要用来调试函数
对一个函数进行调试,注意,这里的function是一个函数或者是方法对象,不再是字符串哦,后面的是参数。当韩树有返回值的时候,函数的返回值就是runcall的返回值。
def myfunc(a,b,c):
return (a/b)/c
result=pdb.runcall(myfunc,100,20,5)
print(result)
5、pdb的其他一些方法
除了上面几个常用的常用方法以外,还有以下几个常用方法,
pdb.
post_mortem
([traceback])
pdb.
pm
()
04
使用ipython和jupyter notebook
进行调试
系列文章的下一篇会介绍,会详细介绍在jupyter里面进行调试的技巧。有兴趣的请关注。
2019/01/05
Saturday
小伙伴们,关于pdb的调试,有没有学习到呢,虽然大部分小伙伴可能从来没有用过原生态的pdb调试方法,但是用习惯了不比任何一个IDE差哦!后面还有系列文章连载,请记得关注哦!如果你有需要,就添加我的公众号哦,里面分享有海量资源,包含各类数据、教程等,后面会有更多面经、资料、数据集等各类干货等着大家哦,重要的是全都是免费、无套路分享,有兴趣的小伙伴请持续关注!
推 荐 阅 读
「2019,不再裸奔」人生最幸福的事情就是有人陪你一路前行!
python标准库系列教程(四)——collections库详细教程
python标准库系列教程(三)——operator库详细教程
python标准库系列教程(二)——functools (下篇)
python标准库系列教程(二)——functools (中篇)
赶紧关注我们吧
您的点赞和分享是我们进步的动力!
↘↘↘