出于本教程的目的,让我们研究一下下面的简单程序。
这个程序接收两个命令行参数,然后执行加法和减法操作。
(假设用户输入的是有效值,因此代码中我们没有进行错误处理。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import
sys
def
add
(
num1
=
0
,
num2
=
0
)
:
return
int
(
num1
)
+
int
(
num2
)
def
sub
(
num1
=
0
,
num2
=
0
)
:
return
int
(
num1
)
-
int
(
num2
)
def
main
(
)
:
#Assuming our inputs are valid numbers
print
sys
.
argv
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
print
addition
subtraction
=
sub
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
print
subtraction
if
__name__
==
'__main__'
:
main
(
)
|
Python提供了一个有用的模块PDB,它实际上是一个交互式源代码调试器。
你需要下面的两行代码来使用此模块。
1
2
|
import
pdb
pdb
.
set_trace
(
)
|
看一下我们修改过的程序,里面包含了一些断点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import
pdb
import
sys
def
add
(
num1
=
0
,
num2
=
0
)
:
return
int
(
num1
)
+
int
(
num2
)
def
sub
(
num1
=
0
,
num2
=
0
)
:
return
int
(
num1
)
-
int
(
num2
)
def
main
(
)
:
#Assuming our inputs are valid numbers
print
sys
.
argv
pdb
.
set_trace
(
)
# <-- Break point added here
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
print
addition
subtraction
=
sub
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
print
subtraction
if
__name__
==
'__main__'
:
main
(
)
|
一旦你设置好断点以后,你就可以像平时一样执行程序。
1
|
python
debugger
.
py
1
2
|
程序将会在遇到的第一个断点处停止执行。
1
2
3
4
|
[
&
#039;debugger.py']
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
15
)
main
(
)
-
&
gt
;
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
(
Pdb
)
|
我们在第14行设置了一个断点,所以我们能看到将要执行的下一行是第15行。可以看到,在执行到第15行之前程序已经停止。
在这里我们有几个选项,让我们在下面步骤中看看一些调试指令。
在你的调试器提示中,输入n运行到下一行。
1
2
3
4
5
|
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
14
)
main
(
)
-
&
gt
;
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
(
Pdb
)
n
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
15
)
main
(
)
-
&
gt
;
print
addition
|
这会执行当前行代码,并准备执行下一行。
我们可以使用n来逐行执行整个程序,但这其实没有什么用处。
可能你已经看到,PDB实际上并没有进入我们的add函数中。下面,就让我们看看其他几个令调试更加有趣的选项。
注意:
一个更酷的特性是你可以单击回车键来执行以前的命令(在本例中只要指令n)。
下面,我们再次开始调试程序。(你可以通过单击c使PDB跳到末尾或者直到下一个断点,因为程序中我们并没有其他的断点了,所有程序将会执行完成。)
1
2
3
4
|
[
&
#039;debugger.py', '1', '2']
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
14
)
main
(
)
-
&
gt
;
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
(
Pdb
)
|
现在,如果我们想知道sys.argv中包含什么内容,我们可以输入以下内容:
1
2
3
4
5
6
|
-
&
gt
;
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
(
Pdb
)
p
sys
.
argv
[
&
#039;debugger.py', '1', '2']
(
Pdb
)
p
sys
.
argv
[
1
]
&
#039;1'
(
Pdb
)
|
使用这种方法可以相当方便地查看变量中实际存储着什么值。
现在我们将进入加法函数内部。
我们可以使用“s”进入加法函数内部。
1
2
3
4
5
6
7
8
|
(
Pdb
)
s
--
Call
--
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
4
)
add
(
)
-
&
gt
;
def
add
(
num1
=
0
,
num2
=
0
)
:
(
Pdb
)
n
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
5
)
add
(
)
-
&
gt
;
return
int
(
num1
)
+
int
(
num2
)
(
Pdb
)
|
这将把我们带入加法函数的内部,现在我们可以在加法函数内部使用n、p和其他的操作指令。
此时单击“r”将会把我们带到前面进入函数的返回语句。
如果你想快速跳转到一个函数的结尾处,那么这个指令将很有用。
前面,在程序运行之前,我们使用pdb.set_trace()设置了一个断点。
不过,经常在调试会话已经开始之后,我们想要在程序中特定的地方添加断点。
这里我们就可以使用选项“b”来实现这种目的。
我们重新开始执行程序。
1
2
3
4
|
[
&
#039;debugger.py', '1', '2']
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
15
)
main
(
)
-
&
gt
;
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
(
Pdb
)
|
此时我在第18行设置一个断点。
1
2
3
4
5
6
7
8
9
10
11
|
-
&
gt
;
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
(
Pdb
)
b
18
Breakpoint
1
at
/
Users
/
someuser
/
debugger
.
py
:
18
(
Pdb
)
c
We
are
in
add
--
3
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
18
)
main
(
)
-
&
gt
;
print
subtraction
(
Pdb
)
p
subtraction
-
1
(
Pdb
)
|
从上面我们可以看到,PDB跳到了第18行并等待下一个指令。
同时,PDB还为该断点分配了一个号码(在本例中是1)。为了以后的执行,我们可以通过开启或禁用断点号码来启用或停用对应的断点。
有时在调试的时候,你可能会忘记此时你处在代码的什么地方。在这种情况下,使用“l”将会打印出一个友好的总结,它能够显示出此刻你在代码中的位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[
&
#039;debugger.py', '1', '2']
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
15
)
main
(
)
-
&
gt
;
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
(
Pdb
)
l
10
11
def
main
(
)
:
12
#Assuming our inputs are valid numbers
13
print
sys
.
argv
14
pdb
.
set_trace
(
)
# <-- Break point added here
15
-
&
gt
;
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
16
print
addition
17
subtraction
=
sub
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
18
print
subtraction
|
9. 动态分配变量
在调试会话期间,你可以分配变量来帮助你进行调试,知道这些对你来说也是有帮助的。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
[
&
#039;debugger.py', '1', '2']
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
15
)
main
(
)
-
&
gt
;
addition
=
add
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
(
Pdb
)
n
We
are
in
add
--
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
16
)
main
(
)
-
&
gt
;
print
addition
(
Pdb
)
p
addition
3
#<--- addition here is 3
(
Pdb
)
addition
=
&
#039;this is now string' #<--- We changed the value of additon
(
Pdb
)
n
this
is
now
string
#<--- Now when we print it we actually gets it as a string. that we just set above.
&
gt
;
/
Users
/
someuser
/
debugger
.
py
(
17
)
main
(
)
-
&
gt
;
subtraction
=
sub
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
|
注意:
如果你想设置一些如n(即PDB指令)这样的变量,你应该使用这种指令:
1
2
3
|
(
Pdb
)
!
n
=
5
(
Pdb
)
p
n
5
|
最后,在代码的任何地方如果你想结束调试,可以使用“q”,那么正在执行的程序将会终止。
本文只涉及到了PDB的表面用法,其实使用PDB你还可以做到更多(PDB 文档)。
使用IPython的人可以在ipdb中找到一个更好的调试器,它提供了tab补充、语法高亮和其他一些很酷的特性。