歡迎光臨
每天分享高質量文章

DeBug Python程式碼全靠print函式?換用這個一天2K+Star的工具吧

(點選上方快速關註並設定為星標,一起學Python)

來源:機器之心     參與:思源         連結
https://mp.weixin.qq.com/s/weEZEr4g8pI11Gijc-St0Q

print 函式已老,DeBug 該靠 PySnooper 了~

小夥伴們,你們都怎樣 DeBug Python 程式碼?是不是常用 print 大法?在本文介紹的這個專案中,deBug Python 程式碼再也不需要 print 了。只要給有疑問的程式碼加上裝飾器,各種資訊一目瞭然,找出錯誤也就非常簡單了。

這個名為 PySnooper 的專案是剛開源的,僅僅一天就獲得了 2K+ 的 Star 量,當然這「一天」還沒結束,這個收藏量也會繼續掃清。

專案地址:https://github.com/cool-RR/pysnooper

Python 怎樣 DeBug?

如果寫著寫著模型,發現模型不 work 了,那麼你該怎樣找出 Python 的錯誤陳述句?這種錯誤一般與語法無關,而是某個變數的運算發生了錯誤。接下來我們就要慢慢找哪個地方有問題了,這裡最常見、最直觀的方法就是 print 大法。把我們懷疑的變數打印出來,總會找到異常的地方。

如果程式碼中嵌入了單元測試,例如 assert 陳述句,那麼還能縮小一些懷疑範圍。但通常我們都要多次嘗試,列印多個變數才能找到錯誤的地方。在 PyTorch 或 Keras 這樣的動態計算圖還好,打印出來的直接是一個值,像 TensorFlow 這樣的靜態計算圖,打印出來是張量資訊而不是值,這就很尷尬了。

實際上不止是機器學習,在我們寫 Python 的時候,總是想搞清楚為什麼寫的程式碼在執行時有點不大對。很多讀者樂於使用斷點等成熟的 DeBug 工具,也有的直接使用 print 大法找錯誤的地方。但現在我們不需要擔心了,本文將介紹一個新的開源工具,它信心滿滿地呼籲到:「不要再使用 print 函式來 DeBug 啦~」

極簡DeBug工具PySnooper

一般情況下,想要知道哪一行程式碼在執行、哪一行不執行、本地變數的值是多少時,大部分人會使用 print 函式,在關鍵部分列印某個或某組變數的值、形狀、型別等資訊。

而 PySnooper 讓你能快速地獲得這些資訊,且相比之下它不需要細緻地寫 print 函式,只需要向感興趣的函式增加一個裝飾器就行了。我們會得到該函式的詳細 log,包含哪行程式碼能執行、什麼時候執行以及本地變數變化的確切時間。

相比於其他程式碼智慧工具,PySnooper 為何如此優秀?因為不需要任何設定,你就可以在劣等、不規則的企業程式碼庫上使用 PySnooper。只需要加個裝飾器,併為日誌輸出地址指定路徑就行了。

這樣說可能不太直觀,下麵我們可以具體看個案例,PySnooper 的優秀就能一目瞭然。

PySnooper 案例

下麵專案作者寫了一個函式以將數值轉換為二進位制碼,該函式傳回的是一個二進位制串列。下麵我們將裝飾器 @pysnooper.snoop() 加到該函式上,就大功告成了。

import pysnooper

@pysnooper.snoop()
def number_to_bits(number):
    if number:
        bits = []
        while number:
            number, remainder = divmod(number, 2)
            bits.insert(0, remainder)
        return bits
    else:
        return [0]

number_to_bits(6)

該函式傳回的日誌如下,我們可以看到在呼叫 number_to_bits 函式時,賦予引數 number 的初始值為 6。然後,PySnooper 就還是對著原始碼一行行分析了。

如上分析所示,函式每建立一個新變數,那麼這個變數的值、這個變數的變化都會展示出來。而且 PySnooper 還將迴圈展開,因此變化的細節更加明確。最終 6 的二進製版本應該是 [1, 1, 0],它的變化過程也展示在 bits 變數中。

現在透過這些詳細資訊,PySnooper 再也不用擔心我們用 print 函式強行 deBug 了。

PySnooper 詳細特徵

如果標準錯誤輸出難以獲得,或者太長了,那麼可以將輸出定位到本地檔案:

@pysnooper.snoop('/my/log/file.log')

檢視一些非本地變數的值:

@pysnooper.snoop(variables=('foo.bar', 'self.whatever'))

展示我們函式中呼叫函式的 snoop 行:

@pysnooper.snoop(depth=2)

將所有 snoop 行以某個字首開始,更容易定位和找到:

@pysnooper.snoop(prefix='ZZZ ')

演示 PySnooper

下麵我們最開始嘗試使用 PySnooper 獲取 TensorFlow 的資訊,如果它能獲取各種張量資訊,那可就太強大了。

首先使用 pip 安裝包:

pip install pysnooper

果然,TensorFlow 這種靜態圖並不能很好地獲取資訊,讀者也可嘗試一下。後面我們試了試 NumPy,希望能獲取整個計算流的資訊。如下程式碼所示,我們建立了兩個陣列變數,並且 2×2 的矩陣會連乘多次,如果能追蹤到這種連乘,那就比較好處理錯誤。

import pysnooper
import numpy as np

@pysnooper.snoop()
def multi_matmul(times):
    x = np.random.rand(22)
    w = np.random.rand(22)

    for i in range(times):
        x = np.matmul(x, w)
    return x

multi_matmul(3)

對於 NumPy,該工具確實能追蹤所有可疑變數的變化過程。當然在實際運算中,矩陣乘法的維度會非常大,我們可以直接追蹤形狀(Shape),而不是具體的值。

    已同步到看一看
    贊(0)

    分享創造快樂