## 调试你的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()


## 3 执行程序以触发debugger

一旦你设置了断点(break points),你就能像平时那样执行程序。


    python debugger.py 1 2


The program will halt execution at the first break point it encounters.

程序将在遇到第一个断点(break point)时暂停执行。


    ['debugger.py']

    > /Users/someuser/debugger.py(15)main()

    -> addition = add(sys.argv[1], sys.argv[2])

    (Pdb)


我们在第14行设置了断点(break point),我们会看到下次被执行的将是第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的有趣方法请在下面评论


排错愉快!