Python里三個好用的調(diào)試神器

調(diào)試是開發(fā)過程中不可避免的一個環(huán)節(jié),在Python中我們使用print、logging、assert等方法進(jìn)行調(diào)試既簡單又實(shí)用,但畢竟有其局限性。今天這篇文章為大家?guī)砣齻€工具,其中有Python的內(nèi)置模塊也有第三方庫,它們提供了調(diào)試代碼所需的大部分常用功能,將極大的提升我們的開發(fā)和bug排除效率。

創(chuàng)新互聯(lián)是一家專注于網(wǎng)站建設(shè)、網(wǎng)站制作與策劃設(shè)計,濟(jì)寧網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10多年,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:濟(jì)寧等地區(qū)。濟(jì)寧做網(wǎng)站價格咨詢:028-86922220

1.PDB

pdb是Python中的一個內(nèi)置模塊,啟用pdb后可以對代碼進(jìn)行斷點(diǎn)設(shè)置和跟蹤調(diào)試。為了演示方便,我們準(zhǔn)備一個樣例程序pdb_test.py:

def countnumber(number):
  for i in range(number):
    print(i)

if __name__ == '__main__':
  countnumber(10)

之后在終端中輸入python -m pdb pdb_test.py命令,進(jìn)入pdb的調(diào)試模式:
Python里三個好用的調(diào)試神器
這時我們就可以通過各種命令控制代碼執(zhí)行或者查看當(dāng)前變量,例如l可以查看所有代碼,n是執(zhí)行下一步代碼,p可以查看當(dāng)前變量等等,需要注意的是命令n只會執(zhí)行主程序中的代碼,如果想要單步執(zhí)行子函數(shù)中的代碼,需要使用s指令,調(diào)試效果如下:
Python里三個好用的調(diào)試神器
這時我們就可以通過各種命令控制代碼執(zhí)行或者查看當(dāng)前變量,例如l可以查看所有代碼,n是執(zhí)行下一步代碼,p可以查看當(dāng)前變量等等,需要注意的是命令n只會執(zhí)行主程序中的代碼,如果想要單步執(zhí)行子函數(shù)中的代碼,需要使用s指令,調(diào)試效果如下:
Python里三個好用的調(diào)試神器
可以看到,通過s指令(如果只想在主函數(shù)中單步執(zhí)行可以使用n)和p指令,我們控制程序單步運(yùn)行并實(shí)時查看了相關(guān)變量。但是單步執(zhí)行畢竟是一種效率非常低下的調(diào)試方式,尤其當(dāng)代碼量比較大的時候更是噩夢,這時就需要用到pdb的set_trace()方法,我們對樣例程序pdb_test.py做一點(diǎn)修改:

'''
遇到問題沒人解答?小編創(chuàng)建了一個Python學(xué)習(xí)交流QQ群:857662006 尋找有志同道合的小伙伴,
互幫互助,群里還有不錯的視頻學(xué)習(xí)教程和PDF電子書!
'''
import pdb
def countnumber(number):
  for i in range(number):
    print(i)
    pdb.set_trace()

if __name__ == '__main__':
  countnumber(10)

pdb.set_trace()的作用就是在代碼中設(shè)置斷點(diǎn),在pdb調(diào)試模式下,使用c命令就會直接跳轉(zhuǎn)到下一個斷點(diǎn)位置,如果之后沒有其他斷點(diǎn)就會執(zhí)行完全部代碼,調(diào)試效果如下:
Python里三個好用的調(diào)試神器
除了上面提到的幾個指令以外,pdb還有其他一些比較常用的命令(見下表),綜合使用基本能夠滿足日常的調(diào)試需求。
Python里三個好用的調(diào)試神器
2.Better-exceptions

better-exceptions是一個Python第三方庫,作者對他的定義是“使異常信息更加美觀和詳盡”。在正式使用之前先說下這個庫的安裝:

第一步,使用pip install better_exceptions安裝better-exceptions庫;
第二步,使用export BETTER_EXCEPTIONS=1(Linux / OSX)或setx BETTER_EXCEPTIONS 1(Windows)設(shè)置環(huán)境變量。

現(xiàn)在就可以正常使用better-exceptions進(jìn)行調(diào)試了,為了演示效果更加明顯,我們對上文中的代碼稍作修改作為本次的樣例程序better_test.py:

def divisionnumber(number, div):
  for i in range(div):
    print(number / i)

if __name__ == '__main__':
  divisionnumber(10, 10)

很明顯,上面這段代碼在執(zhí)行過程中會因?yàn)榉帜笧?而拋出異常,現(xiàn)在我們執(zhí)行python better_test.py,看看啟用了better-exceptions后的異常信息是什么樣子的:
Python里三個好用的調(diào)試神器
從上面這幅圖可以看出better-exceptions對異常信息的修改主要體現(xiàn)在兩個方面:

一是對產(chǎn)生異常的代碼進(jìn)行了顏色標(biāo)注;

二是對產(chǎn)生異常的代碼中的相關(guān)變量值進(jìn)行了輸出(包括函數(shù)等對象);

這樣一來,很多時候我們只需要根據(jù)better-exceptions輸出的輔助信息就能判斷產(chǎn)生異常的位置和原因,而不必像以前一樣再次查看源代碼并觀察運(yùn)行結(jié)果,正如作者所說:Pretty and more helpful。
但是,過多的信息輸出也會有問題,那就是當(dāng)代碼層級結(jié)構(gòu)比較復(fù)雜的時候,better-exceptions輸出的輔助信息可能會非常之多,就比如上面的divisionnumber函數(shù),他所在的地址信息多數(shù)時候我們并不關(guān)心,為了屏蔽這些“垃圾”信息,我們可以在代碼中加一行:

better_exceptions.MAX_LENGTH = XXX

XXX是允許顯示的最大字符長度,比如這里設(shè)置為10,再來運(yùn)行better_test.py這個程序就會是下面的結(jié)果:
Python里三個好用的調(diào)試神器
可以看到,對函數(shù)divisionnumber的注釋只顯示了最開始的"<function"這幾個字符。
除了上面提到的功能之外,better-exceptions還可以和logging還有django無縫接入,這使得它的應(yīng)用更加靈活,關(guān)于這方面內(nèi)容大家可以查看項(xiàng)目文檔。
還有一點(diǎn)需要提醒大家,如果你是在windows下使用,可能會出現(xiàn)下圖中的亂碼問題,這是由于better-exceptions的內(nèi)設(shè)編碼格式所導(dǎo)致的。
Python里三個好用的調(diào)試神器
解決的辦法是在安裝后,對better_exceptions目錄下的encoding.py文件第10行代碼進(jìn)行如下修改:

# 原代碼:
ENCODING = locale.getpreferredencoding()
# 修改為:
ENCODING = 'utf-8'

3.PySnooper

PySnooper也是一個Python的第三方庫,他的特點(diǎn)是能夠精準(zhǔn)的顯示每條代碼的執(zhí)行順序、執(zhí)行時間以及隨之帶來的局部變量的改變等等。值得一提的是,作為一個發(fā)布不滿半年的庫,PySnooper在github上已經(jīng)達(dá)到了1.2W星,其受歡迎程度可見一斑。
Python里三個好用的調(diào)試神器
PySnooper的使用可以說是非常的方便,直接在代碼中以裝飾器的形式調(diào)用就可以了。當(dāng)然在引用前你得使用pip install pysnooper或者conda install -c conda-forge pysnooper安裝這個庫。我們還是舉一個例子來進(jìn)行演示,樣例代碼如下:

'''
遇到問題沒人解答?小編創(chuàng)建了一個Python學(xué)習(xí)交流QQ群:857662006 尋找有志同道合的小伙伴,
互幫互助,群里還有不錯的視頻學(xué)習(xí)教程和PDF電子書!
'''
import pysnooper
import random
@pysnooper.snoop()
def foo():
    lst = []
    for i in range(10):
        lst.append(random.randrange(1, 1000))
    lower = min(lst)
    upper = max(lst)
    mid = (lower + upper) / 2
    print(lower, mid, upper)
foo()

在上面這段代碼中,我們先是生成10個1到1000之間的隨機(jī)數(shù),然后計算他們之中的最大最小值和中位數(shù),唯一的不同在于第三行多了一條語句@pysnooper.snoop(),我們運(yùn)行以下代碼,發(fā)現(xiàn)除了正常的print結(jié)果之外,多了許多內(nèi)容(內(nèi)容太多,下面只顯示一部分):

19:51:57.704857 call        16 def foo():
19:51:57.705860 line 17     lst = []
New var:....... lst = []
19:51:57.705860 line 18     for i in range(10):
New var:....... i = 0
19:51:57.705860 line 19         lst.append(random.randrange(1, 1000))
Modified var:.. lst = [758]
19:51:57.705860 line 18     for i in range(10):
Modified var:.. i = 1

....................

19:51:57.706818 line 22     upper = max(lst)
New var:....... upper = 927
19:51:57.706818 line 23     mid = (lower + upper) / 2
New var:....... mid = 552.0
19:51:57.706818 line 24     print(lower, mid, upper)
19:51:57.706818 return      24     print(lower, mid, upper)
Return value:.. None

這都是PySnooper跟蹤監(jiān)控的結(jié)果,正如上面所說,他準(zhǔn)確記錄的每條代碼的運(yùn)行時間、順序以及相關(guān)的變量值。
作為一個星標(biāo)1.2W+的項(xiàng)目,PySnooper的功能肯定不會這么簡單,@pysnooper.snoop()中是可以接收參數(shù)的,比如我們覺得輸出內(nèi)容太多,可以考慮把信息記錄到log日志中,這個功能只需要加一個log文件定位參數(shù)就能搞定:

@pysnooper.snoop('file.log')

@pysnooper.snoop()支持的參數(shù)還有很多,分別對應(yīng)了不同的功能,例如監(jiān)控自定義表達(dá)式、監(jiān)控底層函數(shù)、支持多線程等等,詳見項(xiàng)目文檔。
此外,pysnooper還支持局部監(jiān)控,一般來說我們寫的代碼都比較長,而需要監(jiān)控的只是其中的一小部分,這時候就可以把需要監(jiān)控的代碼放到一個block里。我們修改下剛才的代碼,只對計算最大最小值和中位數(shù)的部分進(jìn)行監(jiān)控,修改后的代碼如下:

'''
遇到問題沒人解答?小編創(chuàng)建了一個Python學(xué)習(xí)交流QQ群:857662006 尋找有志同道合的小伙伴,
互幫互助,群里還有不錯的視頻學(xué)習(xí)教程和PDF電子書!
'''
import pysnooper
import random
def foo():
    lst = []
    for i in range(10):
        lst.append(random.randrange(1, 1000))
    with pysnooper.snoop():
      lower = min(lst)
      upper = max(lst)
      mid = (lower + upper) / 2
    print(lower, mid, upper)
foo()

運(yùn)行之后發(fā)現(xiàn)監(jiān)控信息精簡了很多:

New var:....... lst = [562, 341, 552, 353, 628, 302, 430, 188, 955, 108]
New var:....... i = 9
20:02:47.359272 line 21       lower = min(lst)
New var:....... lower = 108
20:02:47.359272 line 22       upper = max(lst)
New var:....... upper = 955
20:02:47.360269 line 23       mid = (lower + upper) / 2

使用with pysnooper.snoop()模式依然保留了對各種參數(shù)的支持,個人認(rèn)為這種模式更加符合實(shí)踐需求。

小結(jié):
今天介紹了三個不借助IDE就能方便使用的調(diào)試工具,三個工具的調(diào)試思路和適用場景也各不相同,大家可以根據(jù)需要靈活選用。不過話說回來,我個人最喜歡的還是PySnooper,你最喜歡哪一款呢?

網(wǎng)頁標(biāo)題:Python里三個好用的調(diào)試神器
網(wǎng)站路徑:http://bm7419.com/article12/pcosdc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序Google、品牌網(wǎng)站制作、關(guān)鍵詞優(yōu)化、、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站