Python出现BUG怎么调试的问题。BUG有2种:

第一种,直接造成了错误,程序抛了个异常。楼上已经讲了IPython,是的。首先我先写一个有问题的例子:

 

a = 1
b = 0

a / b


执行肯定是报错的:

 

❯ python test.py
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    a / b
ZeroDivisionError: integer division or modulo by zero


有点经验的人一眼看去就知道 是因为分母是0造成的。可是脚本执行结束了,要是调试还得不断的在对应位置加print。绝招就是:

 

❯ ipython test.py --pdb
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
/Users/dongweiming/test/test.py in <module>()
      2 b = 0
      3 
----> 4 a / b

ZeroDivisionError: integer division or modulo by zero
*** NameError: name 'pdb' is not defined
> /Users/dongweiming/test/test.py(4)<module>()
      1 a = 1
      2 b = 0
      3 
----> 4 a / b

ipdb> p b  # p是print的别名
0
ipdb> p a
1
ipdb> 


程序运行在错误的地方,嘎.. 停住了,保存了错误上下文,进入pdb环境,直接调试去吧,不要太开心。

说到这里,ipdb(pdb)可以设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。它有很多快捷键:

 

ipdb> help

Documented commands (type help <topic>):
========================================
EOF    bt         cont      enable  jump  pdef    psource  run      unt   
a      c          continue  exit    l     pdoc    q        s        until 
alias  cl         d         h       list  pfile   quit     step     up    
args   clear      debug     help    n     pinfo   r        tbreak   w     
b      commands   disable   ignore  next  pinfo2  restart  u        whatis
break  condition  down      j       p     pp      return   unalias  where 


其中up,down,n,j,l,where,s, args等我都非常常用,我非常建议你每个快捷键都了解一下。当然很懒的话,你们也有福利,看 Python 代码调试技巧 。

第二种:隐藏BUG,也就是并没有报错,但是输出不符合预期,这种的比较烦,因为如果你经验少写的时候又不咋专心的话,基本上就得挨个地方去确认,有人说,「import pdb pdb.set_trace() 」,嗯很标准的方案,但是我一般不用。原因是什么呢,比如调试Web应用,如果set_trace()的话,需要点多个next才能到你想调试的地方,手指头都点木了。。所以我一般使用如下三个方法:

1. 抛异常。直接让你想要调试的位置让它先跑个异常,比如Flask的DEBUG的模式下,werkzeug里面的DebuggedApplication就会把Web页面渲染成一个可调试和可执行的环境,直接到上面调试:

2. 在对应位置使用print和logging。这是最基础的玩法。我一般只会在已经心理有数,只是需要看看日志输出来确认的时候加临时的。平时的应用日志也会有常规的记录,并且会记录堆栈(当然,使用sentry之类的方式搜集日志是最好的),比如重要的上线过程中,出了问题但是开发环境又不好模拟出来的时候,「tail -f」日志文件们,这样出现问题一看就看到了。 说到这里再推荐一个很有意思的项目: GitHub – zestyping/q: Quick and dirty debugging output for tired programmers. ,它是在我看pycon2013演讲中发现的,有兴趣可以看看, PyVideo.org · Lightning Talks。我之前常用它。

3. 自己维护一些用于调试的库。我会把工作中常用到的、有用的一些函数、方法搜集起来,放在一个库里。其中有个获取调用栈的函数类似这样:

 

import sys

def get_cur_info():
    print sys._getframe().f_code.co_filename  # 当前文件名
    print sys._getframe(0).f_code.co_name  # 当前函数名
    print sys._getframe(1).f_code.co_name # 调用该函数的函数的名字,如果没有被调用,则返回module
    print sys._getframe().f_lineno # 当前行号


可以通过看当前上下文的调用栈的输出来帮助你揪出那个隐藏的「虫」.


Python在debug方面的支持还是不错的,在明确代码意义的情况下,通过log、print和assert分析错误原因,配合单元测试可以很高效。然而,实际工作中大量代码很可能出自他人之手,这种情况下,使用debugger就显得更加高效了。

一、在控制台下进行程序调试

PDB

如果你熟悉命令行调试工具(例如gdb、lldb),那么使用Python中的PDB将获得非常好的体验,PDB不仅支持项目启动时进行调用,也支持在Python shell中交互式调试;功能上,支持断点、步进、异常捕获和解决、变量查看、变量改写、栈查看甚至字节码查看等。

举个PDB断点调试的例子:

用文本编辑器新建一个文档,就命名为debug1.py吧,输入最简单的Python代码片段:

import pdb
a = "a string"
b= "b string"
pdb.set_trace()
print("next step")

然后运行这个脚本,Windows下面这样运行 :

python debug1.py

然后执行到pdb.set_trace()这句后会自动进入断点调试模式,屏幕会显示类似的信息:

> c:\users\david\documents\debug1.py(5)<module>()
-> print("next step")
(pdb)

PDB显示目前的断点位置,然后你就可以使用PDB调试命令了。

Tips:其他常用命令有:

pp,打印

n,下一步,执行下一步

s,步进,一步步的执行

l,列出,显示断点周围的源代码

c,继续,继续程序的运行

r,返回,继续直到当前函数返回

由PDB引入的VIM、Emacs工具都能很好地实现类似lldb和gdb的效果。同时,结合IPython这一扩展功能shell,其中的魔法命令能够更好地帮助程序调试。这是一般*nix环境下常见的调试组合,配合配置良好的文本编辑工具都能实现不错的类IDE体验。PDB更能进行远程调试,即对远端(如服务器上正在运行着的Python代码)进行调试。几乎所有的debugger工具都是在PDB的功能基础上进行用户界面上的提升。

此外,对于部分框架,尤其是Web框架,进行调试往往需要结合具体的上下文环境(例如Django的开发调试测试需要上下文环境等),PDB交互式调试可以直接挂载在对应的交互环境中(如Django shell)。

Pudb

如果你觉得这样太原始,那么可以尝试pudb,它是基于控制台的debug图形化debugger工具,稍微比pdb直观一点,但仅可以在Linux下运行。

这个图形界面有点原始,不支持鼠标,所以不要用鼠标点。

二、图形界面下的程序调试

如果你更习惯于IDE的整体调试,也没有问题。很多支持Python的IDE,调试功能都十分强大,甚至轻量级编辑器也都具备完善的调试功能。接下来简单介绍几款图形化的IDE工具:

Visual Studio Code

VSC作为一个跨平台的重量级文本编辑器以及轻量级IDE,如今已经得到了越来越多开发者的喜爱,而Anaconda作为Python发行版集成环境,已将VSC作为推荐开发工具。

VSCode量级较轻,但只需要安装一个Python语言支持工具,摇身一变就能成为全功能Python IDE,智能感知、补全、重构、查找定义代码段等编辑功能一应俱全,而且调试功能也十分完整,能在调试模式中涵盖PDB的全部功能,并能在图形界面下简单地进行操作。

如果非要说一个VSCode的弱点的话,应该是其调试工具、解释器的配置没有具体的配置页面,需要通过配置文件来进行修改,这一点或许会给新手带来困惑。

Visual Studio

VS号称宇宙第一IDE,其Python开发工具自然也能带来非常好的体验。在VS2017中,Python开发环境就已经是可选择的安装选项了。对于许多曾经使用VS在Windows下进行其他语言开发工作的人而言,熟悉的快捷键、清晰的环境及不会特别夸张的资源消耗绝对是VS的加分点。

当然,其debugger功能也是一应俱全的。

Spyder

作为开源社区贡献的由Python编写的跨平台IDE,Spyder以轻量、便捷、高度集成为卖点。Spyder允许在多种不同的预设模式下工作,例如类似Matlab式的科学计算交互界面,以及其他应用工程开发形式的界面环境;在编码过程中Spyder可实时提示文档、交互式运行、调试时显示全部变量表,并可一键可视化等,对于数据分析而言具有很好的便利性;同样,它也支持步进跟踪等一系列PDB所提供的调试功能。若是说缺点,界面本身不具时尚感,算吧?

Eclipse + PyDev

Eclipse是最辉煌的开源跨平台多语言IDE之一,有着大量用户的簇拥,自然它也为Python提供了支持。PyDev是Eclipse上的Python开发工具包,提供完整IDE功能,也包含所述的断点、步进等调试功能,Eclipse + PyDev可能是最完整的开源Python IDE解决方案。

PyCharm

或许每一个Python开发者对于PyCharm都不陌生,作为目前最好用的Python IDE,PyCharm保持着一个季度一更新的版本迭代频率,每次更新都能带来功能上的惊喜,并且无论你是数据分析、应用开发者抑或是服务端开发,PyCharm都能提供最好的体验。它是最智能的IDE,能够通过你引用的模块推断提醒你是否需要进入科学计算模式;能够解析代码中存在的其它语言片段(如字符串中的SQL、HTML、JS等);可以结合Jupyter Notebook进行开发和展示;能够通过代码生成UML图,包含图形化的单元测试、覆盖率分析、性能分析工具和并行分析工具;能够远程调试、一键部署,能深入结合各种常见框架提供更好的支持;也能方便地进行图形化debug。

PyCharm的缺点?应该是在设置好解释器后,PyCharm将会对环境中所有的site-package进行解析和抽取,以供智能感知自动补全使用,在这期间IDE对内存和CPU的占用都非常大,但如若您的电脑用一块高速SSD作为硬盘,同时又有足够大的内存,一切便会显得非常完美。

与Visual Studio类似,PyCharm是商业软件,虽然它也提供了免费的社区版,但相比之下,社区版的PyCharm受限的功能较多。不过,如果你还是一名学生,便可以利用自己的教育邮箱申请免费的教育版学生授权,体验与Pro版一致的全部功能。