使用 Pdb 在Python调试
Python的 PDB 模块为我们提供了引人注目的Python代码调试的巨大亮点。这包括:
- 程序的暂停
- 查看每一行代码的执行情况
- 检查变量的值
这个模块已经安装了Python。因此,我们只需要将其导入到我们的代码中即可使用其功能。在此之前,我们必须了解下面提到的一些概念:
- 要导入,我们只需在代码中使用import pdb即可。
- 为了调试,我们将使用pdb.set_trace()方法。现在,在Python 3.7 中, breakpoint()方法也可用于此目的。
- 我们在Python idle 终端上运行它(您可以使用任何 ide 终端来运行)。
让我们从一个由几行代码组成的简单示例开始。
例子:
Python3
# importing pdb
import pdb
# make a simple function to debugg
def fxn(n):
for i in range(n):
print("Hello! ", i+1)
# starting point to debugg
pdb.set_trace()
fxn(5)
Python3
# a simple function
def fxn(n):
for i in range(n):
print("Hello! ", i+1)
# using breakpoint
breakpoint()
fxn(5)
Python3
# importing pdb
import pdb
# define recursive function
def rec_fxn(r):
if r > 0:
# set trace
pdb.set_trace()
rec_fxn(r//2)
else:
print("recursion stops")
return
# set trace at start
pdb.set_trace()
rec_fxn(5)
Python3
# importing pdb
import pdb
# simple function
def fxn(n):
l=[]
for i in range(n):
l.append(i)
# set trace
pdb.set_trace()
return
fxn(5)
Python3
# importing pdb
import pdb
# simple function
def fxn(n):
l = []
for i in range(n):
l.append(i)
return
# set trace
pdb.set_trace()
fxn(5)
Python3
# importing pdb
import pdb
# simple function
def fxn(n):
l = []
for i in range(n):
l.append(i)
print(l)
return
# set trace
pdb.set_trace()
fxn(5)
Python3
# importing pdb
import pdb
# simple function
def fxn(n):
# set trace
pdb.set_trace()
l = []
for i in range(n):
l.append(i)
print(l)
return
fxn(5)
Python3
# importing pdb
import pdb
# simple function
def fxn(n):
l=[]
for i in range(n):
l.append(i)
return
# set trace
pdb.set_trace()
fxn(5)
Python3
# importing pdb
import pdb
# simple function
def fxn(n):
l = []
for i in range(n):
l.append(i)
# set trace
pdb.set_trace()
print(l)
return
fxn(5)
Python3
# importing pdb
import pdb
# simple function
def fxn(i):
print(i)
return
# set trace
pdb.set_trace()
for i in range(5):
fxn(i)
输出:
在这里,我们可以看到,当函数调用完成时,pdb 会执行并请求下一个命令。我们可以在这里使用一些命令,例如
c -> continue execution
q -> quit the debugger/execution
n -> step to next line within the same function
s -> step to next line in this function or a called function
要了解有关不同命令的更多信息,您可以键入 help 并获取所需信息。
现在,我们将在 n 命令的帮助下进一步执行我们的程序。
以类似的方式,我们可以使用 breakpoint() 方法(不需要导入 pdb)。
蟒蛇3
# a simple function
def fxn(n):
for i in range(n):
print("Hello! ", i+1)
# using breakpoint
breakpoint()
fxn(5)
输出:
PDB 调试提供的功能
1. 打印变量或表达式
在使用打印顺序 p 时,您传递了一个由Python评估的清晰度。如果您传递变量名,pdb 会打印其当前值。尽管如此,您还可以做更多的事情来检查正在运行的应用程序的状况。
PDB调试在递归检查变量中的应用
在这个例子中,我们将定义一个带有 pdb trace 的递归函数,并在每次递归调用时检查变量的值。为了打印变量的值,我们将使用一个带有变量名称的简单打印关键字。
蟒蛇3
# importing pdb
import pdb
# define recursive function
def rec_fxn(r):
if r > 0:
# set trace
pdb.set_trace()
rec_fxn(r//2)
else:
print("recursion stops")
return
# set trace at start
pdb.set_trace()
rec_fxn(5)
输出:
检查表达式的示例
这个例子类似于上面的例子,它在计算后打印表达式的值。
蟒蛇3
# importing pdb
import pdb
# simple function
def fxn(n):
l=[]
for i in range(n):
l.append(i)
# set trace
pdb.set_trace()
return
fxn(5)
输出:
2. 逐步移入代码
这是 pdb 提供的最重要的特性。为此使用了两个主要命令,如下所示:
n -> step to next line within the same function
s -> step to next line in this function or a called function
让我们通过一个例子来理解这些的工作原理。
蟒蛇3
# importing pdb
import pdb
# simple function
def fxn(n):
l = []
for i in range(n):
l.append(i)
return
# set trace
pdb.set_trace()
fxn(5)
使用 n 输出:
使用 s 输出:
3. 使用断点
此功能帮助我们在源代码中的特定行动态创建断点。在这里,在这个例子中,我们使用下面给出的命令 b 创建断点:
b(reak) [ ([filename:]lineno | function) [, condition] ]
Without argument, list all breaks.
使用行号参数,在当前文件的这一行设置一个中断。与函数名称,设置在该函数的第一个可执行线路断路。如果存在第二个参数,则它是一个字符串,指定一个表达式,该表达式必须在断点生效之前计算为真。
行号可能以文件名和冒号为前缀,以指定另一个文件(可能尚未加载的文件)中的断点。在 sys.path 上搜索文件; .py 后缀可以省略。
蟒蛇3
# importing pdb
import pdb
# simple function
def fxn(n):
l = []
for i in range(n):
l.append(i)
print(l)
return
# set trace
pdb.set_trace()
fxn(5)
输出:
4. 执行代码直到指定行
使用 unt 像 c 一样继续执行,但是,在比当前行更值得注意的下一行停止。有时,unt 会更有帮助且使用起来更快,而且实际上正是您所需要的。
unt(il) [lineno]
不带参数,继续执行,直到到达编号大于当前编号的行。使用行号,继续执行,直到到达编号大于或等于该行的行。在这两种情况下,也在当前帧返回时停止。
蟒蛇3
# importing pdb
import pdb
# simple function
def fxn(n):
# set trace
pdb.set_trace()
l = []
for i in range(n):
l.append(i)
print(l)
return
fxn(5)
输出:
5. 列出代码
Listing Source code 是另一个功能,可用于跟踪带有行号作为列表的代码。为此使用 ll 命令。
longlist | ll -> List the whole source code for the current function or frame.
让我们通过一个例子来理解 longlist 的工作原理。
蟒蛇3
# importing pdb
import pdb
# simple function
def fxn(n):
l=[]
for i in range(n):
l.append(i)
return
# set trace
pdb.set_trace()
fxn(5)
输出:
6. 显示表达式
就像用 p 和 pp 打印关节一样,您可以使用命令 show [expression] 来建议 pdb 因此显示关节的估计,如果它发生变化,当执行停止时。使用命令 undisplay [expression] 清除展示表达。
display [expression]
如果表达式的值发生变化,则显示表达式的值,每次在当前帧中停止执行。不带表达式,列出当前帧的所有显示表达式。
undisplay [expression]
不再在当前帧中显示表达式。不带表达式,清除当前帧的所有显示表达式。
蟒蛇3
# importing pdb
import pdb
# simple function
def fxn(n):
l = []
for i in range(n):
l.append(i)
# set trace
pdb.set_trace()
print(l)
return
fxn(5)
输出:
7.上下帧
在这里,我们可以将每条轨迹作为一帧进行播放,也可以从一帧移动到另一帧。
w(here)
打印堆栈跟踪,最新的帧在底部。箭头表示“当前帧”,它决定了大多数命令的上下文。 'bt' 是这个命令的别名。
u(p) [count]
将当前帧计数(默认为一)在堆栈跟踪中向上移动(到较旧的帧)。
d(own) [count]
将堆栈跟踪中的当前帧计数(默认为一级)向下移动(到较新的帧)。
蟒蛇3
# importing pdb
import pdb
# simple function
def fxn(i):
print(i)
return
# set trace
pdb.set_trace()
for i in range(5):
fxn(i)
输出: