天天看點

揭秘 IPython 的 5 種最佳調試方法

雲栖号: https://yqh.aliyun.com 第一手的上雲資訊,不同行業精選的上雲企業案例庫,基于衆多成功案例萃取而成的最佳實踐,助力您上雲決策!

一個好的內建開發環境(IDE)附帶的調試器是開發人員能夠擁有的最強大的工具之一,但并不是每個人都在使用一個帶有很棒代碼調試器的內建發環境(IDE)。作為程式員,在調試 Python 代碼時,你覺得最好用的調試器有哪些?如果沒有的話,不妨試試使用 IPython 作為調試器吧。

揭秘 IPython 的 5 種最佳調試方法

以下為譯文:

Tenderlove(Ruby和Rails的核心開發人員之一)寫了一篇很棒的文章,叫做“I am a puts debuggerer”,當我還在玩Ruby的時候,我很喜歡這篇文章。這篇文章的重點是想告訴大家:在許多情況下,你不需要一個成熟的調試器。别誤會我(或者Tenderlove)的意思,我認為,一個好的內建開發環境(IDE)附帶的調試器是開發人員能夠擁有的最強大的工具之一!它能讓你可以很輕松地在代碼中放置斷點、在stack trace中移動、或者動态地檢查和修改變量。它也使開發人員在大型代碼庫上工作更加輕松,并且可以幫助新手程式員加快新項目的進度。

然而,今天的人們仍然會使用print語句來調試他們的代碼。我總是這樣做,因為列印出一個變量既快又容易。“我要開始調試會話”這句話聽起來很沉重,而“我認為這個變量有問題。我想列印出來看看!”就輕松多了。下面就是我們用5分鐘就能寫出的一個print語句的例子:

print(a_varible)

...

if foo:
    print(">>>>>>>>>>>>>>Inside 3rd IF")

...

    print(">>>>>>>>>>>>>>Inside 37th IF")

print(">>>>>>>>>> #@!?#!!!")           

上面的代碼看起來很熟悉吧?使用print語句進行代碼調試是毫無問題的。很多時候,你要做的隻是找出Bug。有時候,這也是你能運用的調試代碼的唯一方法。因為在不影響使用者使用的前提下,你很難将調試代碼添加到生産環境代碼中。然而,僅僅添加一些print語句,然後檢視日志應該不會造成什麼問題。

并不是每個人都在使用一個帶有很棒代碼調試器的內建發環境(IDE)。2019年Stack Overflow開發者調查報告顯示:30.5%的開發人員使用Notepad++,25.4%的開發人員使用Vim,23.4%的開發者使用Sublime Text。這些都是文本編輯器!盡管我看到開發人員在使用Vim時比大多數使用PyCharm或VS Code的使用者更有效率,但是要記住一個文本編輯器并不會帶有強大的代碼調試器。要調試Python代碼,你當然可以使用标準的Python調試器pdb,但是現在你有一個更好的選擇:那就是使用IPython作為調試器。

我使用VS Code已經快兩年了,但我不記得上次使用其内置的調試器是什麼時候。我大部分的調試工作都是在IPython中完成的。以下是我的調試方法:

将IPython會話嵌入到代碼中

對我而言,最常用的做法是在代碼中嵌入一個IPython會話。你隻需要在代碼中插入以下兩行就可以做到:

from IPython import embed
embed()           

我喜歡把這兩行代碼放在同一行,像下面這樣:

from IPython import embed; embed()           

這樣的話,我隻需要敲一次鍵盤就能把它移除掉。而且,在Python中,将多個語句放在同一行是一種壞習慣,是以所有的code linter都會将這行作為一個問題标注出來,這樣的話,當調試完成後,調試就不會忘記把它移除😉。

當你運作代碼并且解釋器到達帶有embed()函數的行時,它将打開一個IPython會話。你可以仔細檢視代碼中發生了什麼。當你完成後,你隻需要使用Ctrl+d關閉會話,代碼将繼續執行。這種方法的一個優點是,當你關閉IPython會話時,你在IPython中所做的所有修改都将儲存下來。是以,你可以用這種方式對變量或函數進行修改(甚至可以用一些簡單的日志來修飾函數),并檢視其餘代碼的行為。

下面是使用embed()的簡短示範。假設我們有以下代碼:

a = 10
b = 15

from IPython import embed; embed()

print(f"a+b = {a+b}")           

下面是我們運作它時發生的情況:

揭秘 IPython 的 5 種最佳調試方法

如上所見,我更改了a變量的值,當我關閉IPython會話後,a的新值保留下來了。

在代碼中放置斷點

如果你想檢視在給定代碼行上發生的情況,在代碼中嵌入一個IPython會話是不錯的做法。但是它不能像真正的調試器那樣,讓你可以執行下一行代碼。是以更好的辦法是在代碼中放置一個斷點。從Python 版本3.7開始,有一個新的名為breakpoint()的内置函數可以用來放置斷點。如果你使用的是較低版本的Python,你可以通過運作以下代碼來實作同樣的效果:

import pdb; pdb.set_trace()           

Python的預設調試器(pdb)相當初級。就像在标準Python REPL(—種互動式解釋器環境。R-read)、E-evaluate)、P-print)、L-loop)中一樣,它沒有文法突出顯示或自動縮進的功能。一個更好的選擇是ipdb。它将使用IPython作為調試器。要啟用它,需要将上面代碼中的pdb替換成ipdb:

import ipdb; ipdb.set_trace()           

還有另一個有趣的調試器PDB++。它有一組不同于ipdb的特性,例如,一個不斷顯示代碼目前位置的粘滞模式。

不管你最終使用哪個調試器,它們都有一組相當标準的指令。你可以通過調用next指令(或者隻是n指令)來執行下一行,通過調用step(或s)指令進入函數内部,使用continue(或c)指令繼續執行直至下一個斷點,使用l或ll指令顯示目前代碼執行的位置,等等。如果你是一個CLI(指令行接口)類型調試器的新手,那麼“使用Pdb調試Python代碼教程”應該對你掌握它們會有幫助。

%run -d filename.py           

IPython還有另外一種方式啟動一個調試器。你不需要像前面那樣修改任何檔案的源代碼。你隻需要運作%run -d filename.py這個神奇的指令,然後IPython将執行filename.py檔案并在其第一行設定一個斷點。作用等同于将import ipdb; ipdb.set_trace()手動放入filename.py檔案中,并且使用python filename.py指令來運作它一樣。

如果要将斷點放在第一行之外的其他位置,可以使用-b參數。以下代碼将斷點放置在第42行的位置:

%run -d -b42 filename.py           

記住,這裡指定的行必須包含實際執行某些操作的代碼。不能是空行或注釋行!

最後,可能存在這樣一種情形:你希望将斷點放在一個不是你将要運作的檔案中。比如說,某個bug可能隐藏在一個導入的子產品中,而你不想再鍵入100次next指令就可以執行到那裡。-b參數可以接受一個檔案名,後跟一個冒号和一個行号,以指定要将斷點确切放置到的位置,修改後的代碼如下:

%run -d -b myotherfile.py:42 myscript.py           

上面的代碼将在名為myotherfile.py的檔案的第42行設定一個斷點,然後開始執行myotherfile.py檔案。一旦Python解釋器到達myotherfile.py,它将在斷點處停止。

事後調試(Post-mortem debugging)

IPython共有176項特性。事後調試是最好的特性,至少對我來說是這樣。假設你正在運作一個長期運作的腳本,在運作了15分鐘後,它突然崩潰了。那麼,你能做的是設定一些斷點,重新運作它,然後再等待15分鐘,看看發生了什麼嗎?如果你用的是IPython,隻要調用一個神奇的指令%debug,你就不必等待了。%debug将加載最後一個異常發生時的stack trace,并且啟動調試器(Python将最後一個未處理的異常存儲在sys.last_traceback變量中)。這是一個很好的特性,它可以讓你直接啟動調試器,節省了幾個小時的重新運作一些指令的時間。

如果使用的是标準pdb調試器,則可以通過運作import pdb; pdb.pm()指令來實作相同的效果。

使用%pdb自動啟動調試器

讓調試更加友善的唯一方法是在發生異常時自動啟動調試器。IPython中的這個神奇的指令 - %pdb就能實作這一點。

如果運作%pdb 1(或%pdb on)指令,調試器将在每個未處理的異常上自動啟動。你可以使用%pdb 0或關閉%pdb on指令關閉這個功能。不帶任何參數運作地運作%pdb将在打開和關閉自動調試器之間進行切換。

原文釋出時間:2020-1-18

本文作者:switowski

本文來自阿裡雲雲栖号合作夥伴“

CSDN

”,了解相關資訊可以關注“

繼續閱讀