调试你的Python代码

调试你的Python代码

译自: http://howchoo.com/g/zgi2y2iwyze/debugging-your-python-code 
作者: Ashley 
    当你不得不更新别人的代码时,你有多少次陷入这样一种境地?如果你是一个开发团队的一员,那我猜一定多于你愿意的次数。 结果我们发现Python (和其他语言一样)提供了在这种情况下便利的debug特性。愿这份快速指南能使你的生活轻松些。

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的,基于交互的源码debug模块。
你需要已如下方式启用该模块。 

import pdb
pdb.set_trace()

 加入断点(break points) 的示例程序:

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

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

我们会看到下次被执行的将是第15行。
程序在执行第15行前暂停了。
我们在这里有一些选择。。。让我们在接下来的步骤中展示其中一部分。

4 下一行 -> n

在debugger提示符处 按”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函数中。让我们在看看debugger的其他选项,使排错变得更有趣。 

 注意:
 另一个酷酷的特性是按回车键会执行你之前执行过的命令(本例中为”n”)。

5 打印 ->p

让我们再次开始debug吧!(既然我们没有任何程序会执行完。你可以敲击”c”使pdb跳至最后或者下一个断点(break point) 

['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)

 这在检测变量实际存储的值时非常有用。
现在让我们进入add函数内部

6 进入函数 -> s

我们可以通过使用”s”来进入我们的addition函数。

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

 这使我们来到了add函数的内部,现在我们能够在其中使用”n, p”以及其他操作了。
这时敲击”r”会跳转至所进入函数的返回语句处。(译注:再次敲击时会跳转至函数调用处)
这在你想快速跳转至方法结尾时很有用。

7 动态添加断点(break point) -> b

我们在运行程序前通过pdb.set_trace()设置了断点(break point)
通常在debugger开始后,我们会想在一些特定的位置设置断点(break point)
好基友 “b” 登场。
让我们再次执行我们的程序

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

现在我在第18行设置一个断点(break point)。

-> 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)。我们能够使用(原文为”user” 疑似笔误)
enable/disable 断点(break point)数字再进一步执行中启用或关闭相对应的断点(break point)。

8 列表 -> l

有时在debug的过程中,你会迷失于代码中。此时,你可以使用”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 给变量动态赋值

在debug时,能给变量赋值也有助于排错。
假设:

['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的表面。还有更多的文档在向你招手!
那些使用ipython的能够在ipdb中找到更好的debugger:tab补全,语法高亮以及其他酷酷的特性。
如果你有其他使用pdb的有趣方法请在下面评论
排错愉快!

原创文章,作者:octopus,如若转载,请注明出处:http://www.178linux.com/1395

(0)
octopusoctopus
上一篇 2015-03-23
下一篇 2015-03-23

相关推荐

  • python安装失败原因分析(未指定错误0x80072efd)

    python安装时间很长,最终报错未指定错误0x80072efd   原因分析: download dubugging symbols download debug binaries 这两项需要联网(外网),国内安装会超时报错。所以安装时取消这两项就可以安装成功      

    2018-08-09
  • 通过堡垒机代理SSH运行Ansible(译)

    有一种常见的网络安全模式是阻止私有网络外部对应用服务器的所有连接(指除了业务数据外其它的连接,如后台管理系统和内部业务系统。译者注),然后使用 DMZ 区域中的 堡垒机 来选择性的将到服务器的流量加入白名单。 我们有这样的一个服务器池,只允许来自特定 IP 地址的 SSH 流量。这些服务器还由 Ansible…

    Linux干货 2015-02-14
  • 几个python运维面试题及答案

    1.生成随机的20个ID ID格式要求: 时间戳_三位随机数字号码_8位随机小写字母 1506571959_089_xxkeabef datetime.datetime.now().timestamp() 返回的是时间戳,但是带微秒 2.判断密码强弱 要求密码必须由 10-15位 指定字符组成: 十进制数字 大写字母 小写字母 下划线 要求四种类型的字符都要…

    2017-10-02
  • 基于Python和MoviePy库实现数据的动态展示

    基于Python和MoviePy库实现数据的动态展示 (翻译:以马内利)  原文链接:Data Animations With Python and MoviePy   Python拥有很多实现数据可视化的库,但是很少可以展示GIFs的动态视图。 这篇博客主要介绍怎样使用MoviePy库作为一个其他可视化库的通用插件。 Movi…

    2015-03-26
  • Python模拟java的do while循环

    在java中有这样的语句: do{    //dosomething}while(条件A); 在python中没有do-while这样的语法,这也是python中“解决一个问题最好只有一个方法”的体现,那么python中怎么模拟do-while语句呢?可以这样: while True:  &nbsp…

    Python干货 2015-03-08