前言
调试线上的 Python 程序时,虽然 PyCharm 可以实现远程调试,但 pdb 才是最便捷的方式,本文简单介绍 pdb 工具的使用,希望各位除了掌握 PyCharm 调试技巧外,还可以掌握 pdb 的最基本用法。
学习一个调试工具,可以从最关键的 4 个功能开始学习:
1. 如何设置断点(新增、删除)
2. 如何执行断点代码
3. 如何查看内存中的数据
4. 如何操作内存中的数据
pdb 是 python 内置的调试工具,不需要额外安装,我们直接开搞。
1. 如何设置断点
准备一段简单的代码,比如计算斐波那契数列的代码(习惯性的以斐波那契举例...)。
def Fibonacci(n):
a, b = 0, 1
while n > 0:
a, b = b, a + b
print(b)
n -= 1
Fibonacci(10)
设置断点分两种,一种是侵入式的添加断点,需要在希望被断点处添加 **「import pdb;pdb.set_trace ()」,另一种则是非入侵式的添加断点,通过 - m 指定参数指定通过 pdb 来运行项目,完整命令为「python3 -m pdb 斐波那契数列.py」**,该命令会将断点打在程序的入口。
随后可以通过 **「l」** 命令来查看断点周围的 11 行项目代码,断点所在位置会通过「->」符号标记出来,如下。
(Pdb) l
1 def Fibonacci(n):
2 a, b = 0, 1
3 while n > 0:
4 import pdb;pdb.set_trace()
5 -> a, b = b, a + b
6 print(b)
7 n -= 1
8
9 Fibonacci(10)
[EOF]
如果多次使用「l」命令,则可以实现翻页查看当前断点下的代码,如果需要查看当前函数或模块的所有代码,则可以使用 **「ll」** 命令。
调试线上代码通常会通过非入侵式的方式进行调试,然后通过 **「b」** 命令添加断点,该命令几种使用方式:
1. 单独使用「b」命令只是查看断点设置
2. 使用「b lineno」命令会在当前模块的对应行数(lineno)添加断点
3. 使用「b filename:lineno 」命名会在某个文件(filename)的对应行(lineno)添加断点
4. 使用「b function」命令会在某个方法(function)的第一行设置断点
简单使用一下。
(Pdb) b 7 # 在第7行添加断点
Breakpoint 1 at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:7
(Pdb) b 斐波那契数列.py:8 # 在 斐波那契数列.py 文件的第8行添加断点
Breakpoint 2 at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:8
(Pdb) b Fibonacci # 在名为 Fibonacci 函数的第1行添加断点
Breakpoint 3 at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:1
(Pdb) b # 查看断点状态
Num Type Disp Enb Where
1 breakpoint keep yes at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:7
2 breakpoint keep yes at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:8
3 breakpoint keep yes at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:1
(Pdb)
此外可以通过 **「tbreak」** 命令添加临时断点,所谓临时断点就是使用一次后,断点将会被清楚,这可以运用在循环体中,一个循环,如果通过命令「b」打断点,那么每次循环处理都会卡在命令「b」设下的断点处,如果使用「tbreak」命令,断点只会在循环体中生效一次。
「tbreak」命令的使用方式如下,与命令「b」的参数一致
tbreak
tbreak lineno
tbreak filename:lineno
tbreak functionname
如果希望清楚某个断点,可以使用 **「cl」命令 **,该命令的几种使用方式如下:
1. 单独使用「cl」命令会清除所有的断点,包括临时断点,在执行清理前会提示确认
2. 使用「cl filename:lineno」命令可以清除某个文件中具体某一行的断点
简单使用一下。
(Pdb) b # 查看当前断点状态
Num Type Disp Enb Where
1 breakpoint keep yes at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:1
2 breakpoint keep yes at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:2
3 breakpoint keep yes at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:7
(Pdb) cl 斐波那契数列.py:7 # 删除 斐波那契数列.py 文件中第7行对应的断点
(Pdb) b # 查看当前断点状态
Num Type Disp Enb Where
1 breakpoint keep yes at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:1
2 breakpoint keep yes at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:2
(Pdb) cl # 清理所有的断点
Clear all breaks? y
Deleted breakpoint 1 at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:1
Deleted breakpoint 2 at /Users/ayuliao/Desktop/workspace/test/斐波那契数列.py:2
(Pdb) b
(Pdb)
2. 如何执行断点代码
pdb 中提供了多种命令实现代码的执行,总体可以分为逐行执行命令与非逐行执行命令。
**「s」、「n」、「r」** 这 3 个命令非常相似,都可以逐行执行代码,其主要的区别在于如何对待函数。
1.「s」命令会执行下一行代码,如果下一行是某函数的调用,则会进入函数体中
2.「n」命令会执行下一行,遇到函数调用并不会进入函数体
3.「r」命令同样会执行下一行代码,遇到函数调用会直接执行到函数体的最后一行
如果希望非逐行执行代码,则可以使用 **「c」命令或「unt」命令 **。
1.「c」命令会执行到下一个断点所在位置,如果是最后一个断点了,那么就会执行完整个程序
2.「unt lineno」命令会执行到指定的某一行或者下一个断点所在位置。
此外,通过 **「j」** 命令要可以跳转到某一行,但该命令会直接跳过中间的代码,不去执行。
3. 如何查看内存中的数据
在某个位置打断点的目的是为了知道程序执行到当前位置其各种变量状态是否正常,这就需要通过某种方法查看内存中的数据了。
最常用的便是通过 **「p」命令查看当前内存中某个变量的值,类似于在代码中使用 print () 方法打印某个变量一样,如果打印的是一个具有复杂结构的变量,可以通过「pp」命令将打印输出的结果美化,如果需要知道变量的类型,可以通过「whatis」** 命令来查看。
此外,如果断点在函数体中,可以通过 **「a」** 命令查看当前函数体的参数和这些参数对应的值。
简单使用一下上述几个命令。
(Pdb) p a # 查看变量a的值
0
(Pdb) whatis a # 查看变量a的类型
<class 'int'>
(Pdb) a # 查看Fibonacci方法的参数名与参数对应的值
n = 10
(Pdb) pp b # 查看变量b的值
1
(Pdb)
4. 如何操作内存中的数据
pdb 提供了多种方法来操作当前断点处内存中的数据,最常用的便是使用 **「interact」** 命令进入交互式解释器中对当前内存中的数据进行各种操作。
在 interact 状态下修改内存中的数据并不会对程序产生实质的影响,所有修改在退出 interact 状态后将被清除。
在 Windows 系统中,通过「ctrl+d」便可以退出 interact 状态,返回 pdb,而在 MacOS 系统中,需要通过「control+d」命令来退出 interact 状态。
简单使用一下。
(Pdb) interact # 进入交互式解释器中操作当前内存中的数据
*interactive*
>>> a
0
>>> a = a + 1 # 修改当前内存中变量a的值
>>> print(a)
1
>>> b
1
>>> ^D # control+d退出interact状态
now exiting InteractiveConsole...
(Pdb) p a # 查看变量a,其值未被改变
0
结尾
pdb 是一款简单的工具,掌握它可以让你在没有 IDE 的工作环境轻松 debug Python 代码。
如果文章对应有所帮助,请点击「在看」或「赞赏」,这是对我最大的鼓励。