使用Python中PDB模块中的命令来调试Python代码的教程


Posted in Python onMarch 30, 2015

你有多少次陷入不得不更改别人代码的境地?如果你是一个开发团队的一员,那么你遇到上述境地的次数比你想要的还要多。然而,Python中有一个整洁的调试特性(像其他大多数语言一样),在这种情况下使用非常方便。本文是一篇快速教程,希望它能让你的编码生活更加容易。
1. 一个混乱的程序

出于本教程的目的,让我们研究一下下面的简单程序。

这个程序接收两个命令行参数,然后执行加法和减法操作。

(假设用户输入的是有效值,因此代码中我们没有进行错误处理。)
 

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()

2. PDB

Python提供了一个有用的模块PDB,它实际上是一个交互式源代码调试器。

你需要下面的两行代码来使用此模块。
 

import pdb
pdb.set_trace()

看一下我们修改过的程序,里面包含了一些断点。
 

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()

3. 程序执行触发调试器

一旦你设置好断点以后,你就可以像平时一样执行程序。
 

python debugger.py 1 2

程序将会在遇到的第一个断点处停止执行。
 

['debugger.py']
> /Users/someuser/debugger.py(15)main()
-> addition = add(sys.argv[1], sys.argv[2])
(Pdb)

我们在第14行设置了一个断点,所以我们能看到将要执行的下一行是第15行。可以看到,在执行到第15行之前程序已经停止。

在这里我们有几个选项,让我们在下面步骤中看看一些调试指令。
4. 下一行->n

在你的调试器提示中,输入n运行到下一行。
 

> /Users/someuser/debugger.py(14)main()
-> addition = add(sys.argv[1], sys.argv[2])
(Pdb) n
> /Users/someuser/debugger.py(15)main()
-> print addition

这会执行当前行代码,并准备执行下一行。

我们可以使用n来逐行执行整个程序,但这其实没有什么用处。

可能你已经看到,PDB实际上并没有进入我们的add函数中。下面,就让我们看看其他几个令调试更加有趣的选项。

    注意:
    一个更酷的特性是你可以单击回车键来执行以前的命令(在本例中只要指令n)。

5. 打印->p

下面,我们再次开始调试程序。(你可以通过单击c使PDB跳到末尾或者直到下一个断点,因为程序中我们并没有其他的断点了,所有程序将会执行完成。)
 

['debugger.py', '1', '2']
> /Users/someuser/debugger.py(14)main()
-> addition = add(sys.argv[1], sys.argv[2])
(Pdb)

现在,如果我们想知道sys.argv中包含什么内容,我们可以输入以下内容:
 

-> addition = add(sys.argv[1], sys.argv[2])
(Pdb) p sys.argv
['debugger.py', '1', '2']
(Pdb) p sys.argv[1]
'1'
(Pdb)

使用这种方法可以相当方便地查看变量中实际存储着什么值。

现在我们将进入加法函数内部。
6. 单步->s

我们可以使用“s”进入加法函数内部。

(Pdb) s
--Call--
> /Users/someuser/debugger.py(4)add()
-> def add(num1=0, num2=0):
(Pdb) n
> /Users/someuser/debugger.py(5)add()
-> return int(num1) + int(num2)
(Pdb)

这将把我们带入加法函数的内部,现在我们可以在加法函数内部使用n、p和其他的操作指令。

此时单击“r”将会把我们带到前面进入函数的返回语句。

如果你想快速跳转到一个函数的结尾处,那么这个指令将很有用。
7. 动态添加断点- > b

前面,在程序运行之前,我们使用pdb.set_trace()设置了一个断点。

不过,经常在调试会话已经开始之后,我们想要在程序中特定的地方添加断点。

这里我们就可以使用选项“b”来实现这种目的。

我们重新开始执行程序。
 

['debugger.py', '1', '2']
> /Users/someuser/debugger.py(15)main()
-> addition = add(sys.argv[1], sys.argv[2])
(Pdb)

此时我在第18行设置一个断点。
 

-> 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
> /Users/someuser/debugger.py(18)main()
-> print subtraction
(Pdb) p subtraction
-1
(Pdb)

从上面我们可以看到,PDB跳到了第18行并等待下一个指令。

同时,PDB还为该断点分配了一个号码(在本例中是1)。为了以后的执行,我们可以通过开启或禁用断点号码来启用或停用对应的断点。
8. 列表->l

有时在调试的时候,你可能会忘记此时你处在代码的什么地方。在这种情况下,使用“l”将会打印出一个友好的总结,它能够显示出此刻你在代码中的位置。
 

['debugger.py', '1', '2']
> /Users/someuser/debugger.py(15)main()
-> 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 ->   addition = add(sys.argv[1], sys.argv[2])
 16     print addition
 17     subtraction = sub(sys.argv[1], sys.argv[2])
 18     print subtraction

9. 动态分配变量

在调试会话期间,你可以分配变量来帮助你进行调试,知道这些对你来说也是有帮助的。例如:
 

['debugger.py', '1', '2']
> /Users/someuser/debugger.py(15)main()
-> addition = add(sys.argv[1], sys.argv[2])
(Pdb) n
We are in add--
> /Users/someuser/debugger.py(16)main()
-> print addition
(Pdb) p addition
3 #<--- addition here is 3
(Pdb) addition = '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.
> /Users/someuser/debugger.py(17)main()
-> subtraction = sub(sys.argv[1], sys.argv[2])

注意:
如果你想设置一些如n(即PDB指令)这样的变量,你应该使用这种指令:
 

(Pdb) !n=5
(Pdb) p n
5

10. 结束->q

最后,在代码的任何地方如果你想结束调试,可以使用“q”,那么正在执行的程序将会终止。
11. 扩展阅读

本文只涉及到了PDB的表面用法,其实使用PDB你还可以做到更多(PDB 文档)。

使用IPython的人可以在ipdb中找到一个更好的调试器,它提供了tab补充、语法高亮和其他一些很酷的特性。

Python 相关文章推荐
python如何对实例属性进行类型检查
Mar 20 Python
Python 网络爬虫--关于简单的模拟登录实例讲解
Jun 01 Python
Python中存取文件的4种不同操作
Jul 02 Python
详解将Django部署到Centos7全攻略
Sep 26 Python
python暴力解压rar加密文件过程详解
Jul 05 Python
使用Python测试Ping主机IP和某端口是否开放的实例
Dec 17 Python
解决python replace函数替换无效问题
Jan 18 Python
浅谈SciPy中的optimize.minimize实现受限优化问题
Feb 29 Python
在tensorflow下利用plt画论文中loss,acc等曲线图实例
Jun 15 Python
Python调用C/C++的方法解析
Aug 05 Python
python 下划线的不同用法
Oct 24 Python
http通过StreamingHttpResponse完成连续的数据传输长链接方式
Feb 12 Python
深入讨论Python函数的参数的默认值所引发的问题的原因
Mar 30 #Python
使用Python标准库中的wave模块绘制乐谱的简单教程
Mar 30 #Python
Python中使用语句导入模块或包的机制研究
Mar 30 #Python
优化Python代码使其加快作用域内的查找
Mar 30 #Python
Python中分数的相关使用教程
Mar 30 #Python
Python2.x中str与unicode相关问题的解决方法
Mar 30 #Python
分享一个常用的Python模拟登陆类
Mar 29 #Python
You might like
php下删除字符串中HTML标签的函数
2008/08/27 PHP
PHP图片等比例缩放生成缩略图函数分享
2014/06/10 PHP
大家在抢红包,程序员在研究红包算法
2015/08/31 PHP
简介PHP的Yii框架中缓存的一些高级用法
2016/03/29 PHP
php自动载入类用法实例分析
2016/06/24 PHP
HTML5附件拖拽上传drop &amp; google.gears实现代码
2011/04/28 Javascript
Javascript中的回调函数和匿名函数的回调示例介绍
2014/05/12 Javascript
jQuery和hwSlider实现内容响应式可触控滑动切换效果附源码下载(二)
2016/06/22 Javascript
JavaScript编写一个简易购物车功能
2016/09/17 Javascript
JavaScript异步上传图片文件的实例代码
2017/07/04 Javascript
Vue上传组件vue Simple Uploader的用法示例
2017/08/25 Javascript
jQuery实现IE输入框完成placeholder标签功能的方法
2017/09/20 jQuery
vue中使用sessionStorage记住密码功能
2018/07/24 Javascript
Vue 动态添加路由及生成菜单的方法示例
2019/06/20 Javascript
vue 百度地图(vue-baidu-map)绘制方向箭头折线实例代码详解
2020/04/28 Javascript
使用vue实现通过变量动态拼接url
2020/07/22 Javascript
javascript实现支付宝滑块验证码效果
2020/07/24 Javascript
Vue elementui字体图标显示问题解决方案
2020/08/18 Javascript
vue等两个接口都返回结果再执行下一步的实例
2020/09/08 Javascript
Python基本语法经典教程
2016/03/11 Python
Python中对象迭代与反迭代的技巧总结
2016/09/17 Python
python如何使用正则表达式的前向、后向搜索及前向搜索否定模式详解
2017/11/08 Python
python机器学习理论与实战(一)K近邻法
2021/01/28 Python
python unittest实现api自动化测试
2018/04/04 Python
Python安装及Pycharm安装使用教程图解
2019/09/20 Python
python中如何设置代码自动提示
2020/07/15 Python
python入门教程之基本算术运算符
2020/11/13 Python
Original Penguin美国官网:布拉德皮特、强尼德普喜爱的服装品牌
2016/10/25 全球购物
俄罗斯品牌服装和鞋子的在线商店:KUPIVIP
2019/10/27 全球购物
扩大国家免疫规划实施方案
2014/03/21 职场文书
我的长征观后感
2015/06/09 职场文书
婚宴致辞
2015/07/28 职场文书
离婚协议书范本(2016最新版)
2016/03/18 职场文书
JavaGUI模仿QQ聊天功能完整版
2021/07/04 Java/Android
ElementUI实现el-form表单重置功能按钮
2021/07/21 Javascript
《LOL》“克隆大作战”久违归来 幻灵战队皮肤上线
2022/04/03 其他游戏