Python 程序如何高效地调试?

做者:Rui L
连接:https://www.zhihu.com/question/21572891/answer/26046582
来源:知乎
著做权归做者全部,转载请联系做者得到受权。

这个要怒答一发。
应该用过 IPython 吧?想象一下,抛出异常时自动把你带到 IPython Shell 是否是很开心?并且和普通的IPython不一样,这个时候能够调用 p (print), up(up stack), down(down stack) 之类的命令。还能建立临时变量,执行任意函数。

事实上这是能够实现的, 并且很简单,不过你要先安装 IPython。而后把如下代码保存为 `crash_on_ipy.py`
import sys class ExceptionHook: instance = None def __call__(self, *args, **kwargs): if self.instance is None: from IPython.core import ultratb self.instance = ultratb.FormattedTB(mode='Plain', color_scheme='Linux', call_pdb=1) return self.instance(*args, **kwargs) sys.excepthook = ExceptionHook() 
而后在你的项目代码某个地方 import crash_on_ipy 就能够了。
这个方法不须要 IDE.
 
 
想要类gdb的功能,可使用pdb,例如:

import pdb
pdb.set_trace()

将上面2行加入到须要加断点的代码处,运行时,执行在此处便可中断,单步、继续、查看变量值等功能都有,不妨help下。
做者:董伟明
连接:https://www.zhihu.com/question/21572891/answer/123220574
来源:知乎
著做权归做者全部,转载请联系做者得到受权。

看LZ的意思是想了解出现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 # 当前行号
能够经过看当前上下文的调用栈的输出来帮助你揪出那个隐藏的「虫」
相关文章
相关标签/搜索