python高级调试技巧(二)——原生态的pdb调试的细节补充

前言:我前面专门写过关于使用python原生调试器的文章,但是缺少一个实例来说明,本文将在之前的基础之上来继续说明python原生pdb里面的一些问题,一些最基础的东西这里就不再说明了,主要是对前面文章的补充。参见:

https://mp.weixin.qq.com/s/59A7ycVa7BUUV4Onmum8Dg

一、实例代码如下:

# python_pdb.py 文件名

import sys
import numpy as np

def func_loop_01(n):
    result=0
    for i in np.arange(n):
        result+=i

    return result

def func_loop_02(n,m):
    temp=func_loop_01(n)  # 在func_loop_02里面调用第二个函数func_loop_01
    return np.add(temp,m)

def run(n,m):
    result=func_loop_02(n,m) # 在run里面调用第二个函数func_loop_02
    return result


if __name__=='__main__':
    s=run(5,2)  # 在主模块中调用第一个函数run
    print(s)

现在启动该程序,用调试的方式启动

python -m pdb python_pdb.py

二、调试的细节查看

由于本程序还未添加任何断点,当我们启动程序开始调试的时候,将会直接显示要执行的第一句代码,即

import sys

下面会讲起一些细节的东西,包括如何添加代码

2.1 什么是python的堆栈信息

知识储备,三个概念:

(1)堆(Heap)通常是一个可以被看做一棵树的数组对象。

(2)栈(Stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。它的特性是先进后出,即FIFO(first in first out)

(3)队列(Queue)先进先出(First-in, First-out)

所以我们说的堆栈,本质上指的是一个栈stack,和堆是不一样的东西哦!

说得明白一点,python的堆栈信息就是显示出函数的层层调用关系,比如在主模块中调用了函数a,在a中调用了函数b,在b中调用了函数c,则堆栈信息为“主模块——>函数a——>函数b——>函数c”,当然我们有专门的方法来查看当前执行位置所处的堆栈位置,后面会讲到如何使用sys模块来查看堆栈信息,本文只涉及到在pdb调试的时候如何查看堆栈信息,

主要涉及到3个调试命令,分别是:

w:(where)打印当前执行堆栈
d:(down)执行跳转到在当前堆栈的深一层(个人没觉得有什么用处)
u:(up)执行跳转到当前堆栈的上一层

比如针对上面代码,我们首先进入到pdb调试模式,


(tensorflow1.12.0) F:\LaneNet\pdb_tfpdb>python -m pdb python_pdb.py # 启动调试

> f:\lanenet\pdb_tfpdb\python_pdb.py(1)<module>()
-> import sys

(Pdb) w     # 查看当前堆栈
#------------------------------------------------------------------------------------
  d:\programdata\anaconda3\envs\tensorflow1.12.0\lib\bdb.py(434)run() #这是最低层的堆栈,即所谓的栈底,即表明程序是通过bdb.py来启动的
-> exec(cmd, globals, locals)

  <string>(1)<module>()   # 第二层栈

> f:\lanenet\pdb_tfpdb\python_pdb.py(1)<module>() # 第三层栈。这就话就是当前堆栈所处的位置,由于当前还未进入到函数调用,在主模块module上,所以堆栈信息只有这一个,这里的虚线是我自己画的,方便看的
#-------------------------------------------------------------------------------------
-> import sys
(Pdb)

然后我们在21行,即s=run(5,2)添加断点,使用 b 21 添加断点,并且运行至断点处,使用c命令即可,然后执行s,进入到run函数里面,再次执行w命令,得到:

(Pdb) w
  d:\programdata\anaconda3\envs\tensorflow1.12.0\lib\bdb.py(434)run() # 第一层堆栈
-> exec(cmd, globals, locals)
  <string>(1)<module>()                                               # 第二层堆栈
#-----------------------------------------------------------------------------------
  f:\lanenet\pdb_tfpdb\python_pdb.py(21)<module>() # 第三层堆栈,module表明这是模块
-> s=run(5,2)  
> f:\lanenet\pdb_tfpdb\python_pdb.py(15)run()      # 第四层堆栈,run()表示这是函数
#------------------------------------------------------------------------------------
-> def run(n,m):

然后继续单步执行s,直到进入到func_loop_02函数,再次执行w查看

(Pdb) w
  d:\programdata\anaconda3\envs\tensorflow1.12.0\lib\bdb.py(434)run()
-> exec(cmd, globals, locals)
  <string>(1)<module>()
#-------------------------------------------------------------------------------------
  f:\lanenet\pdb_tfpdb\python_pdb.py(21)<module>()     # 第三层堆栈
-> s=run(5,2) 
  f:\lanenet\pdb_tfpdb\python_pdb.py(16)run()          # 第四层堆栈
-> result=func_loop_02(n,m) 
> f:\lanenet\pdb_tfpdb\python_pdb.py(12)func_loop_02() # 第五层堆栈
#-------------------------------------------------------------------------------------
-> temp=func_loop_01(n) 

同样的操作,再次继续执行,进入到func_loop_01函数里面,再次查看堆栈信息,得到:

(Pdb) w
  d:\programdata\anaconda3\envs\tensorflow1.12.0\lib\bdb.py(434)run()
-> exec(cmd, globals, locals)
  <string>(1)<module>()
#-------------------------------------------------------------------------------------
  f:\lanenet\pdb_tfpdb\python_pdb.py(21)<module>()     # 第三层堆栈
-> s=run(5,2) 
  f:\lanenet\pdb_tfpdb\python_pdb.py(16)run()          # 第四层堆栈
-> result=func_loop_02(n,m) 
  f:\lanenet\pdb_tfpdb\python_pdb.py(12)func_loop_02() # 第五层堆栈
-> temp=func_loop_01(n)  
> f:\lanenet\pdb_tfpdb\python_pdb.py(5)func_loop_01()  # 第六层堆栈,这里已经到栈顶了
#-------------------------------------------------------------------------------------
-> result=0

当在当前所处的堆栈的时候,我们可以使用u(查看上一层堆栈)d(查看下一层堆栈),比如我现在在func_loop_01函数里面,堆栈信息如上,我执行下面的操作,连续执行两次u,即up,得到

(Pdb) u
> f:\lanenet\pdb_tfpdb\python_pdb.py(12)func_loop_02() # 上一层是func_loop_02
-> temp=func_loop_01(n)   # 并且从func_loop_02跳转到func_loop_01是这一句话
(Pdb) u
> f:\lanenet\pdb_tfpdb\python_pdb.py(16)run()          # 再上一层是run
-> result=func_loop_02(n,m)
(Pdb) u
> f:\lanenet\pdb_tfpdb\python_pdb.py(21)<module>()     # 再上一层是module
-> s=run(5,2)  # 在主模块中调用第一个函数run

使用w、u、d的注意事项:

(1)当up到最下面的一层堆栈,即栈底的时候,再继续up,会显示*** Oldest frame,表明已经到了最底层堆栈;当down到最顶层栈顶的时候,再继续down,则会显示*** Newest frame,表示已经到了栈顶。

(2)up和down只能够查看堆栈的上下层信息,但是并不会改变程序执行的位置,程序执行到哪里了并不会改变,比如我现在程序在执行func_loop_02的语句,然后使用up查看了上一层的堆栈,再次使用s执行的依然是当前的位置,并不会跳转到上一层执行。

2.2 常见的命令区别以及调试步骤

我们调试一个程序一般当然不会,也不需要从整个文件的第一行开始执行,所以我们先需要设置断点

(1)第一步:设置断点,b line 命令,详细的可以参考文章开头的链接,即系列文章的第一篇。

(2)第二步:执行到断点所在的位置,即 c 命令。c:(continue)继续执行,直到遇到下一条断点,这个比较重要,常常和断点结合起来使用。

(3)常见的一些命令:

s:(step)执行下一条命令,如果本句是函数调用,则s会进入函数,并开始执行到函数的第一句
n:(next)执行下一条语句,如果本句是函数调用,则执行完整个函数,接着执行当前执行语句的下一条。

(注意s 和 n 的区别哦)

r:(return)执行当前运行函数到结束,即直接运行到函数的最后一行
unt:(until)执行到下一行,如果是在一个循环里面,则会跳出循环执行循环后面的语句(跳出循环),

注意区别上面这几个的用法和区别。

其他的一些命令,就参考前一篇文章吧:

   https://mp.weixin.qq.com/s/59A7ycVa7BUUV4Onmum8Dg

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值