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 # 當前行號
能夠經過看當前上下文的調用棧的輸出來幫助你揪出那個隱藏的「蟲」
相關文章
相關標籤/搜索