注意:本文方法僅限于調試安裝時附帶py源碼的庫,如sklearn 。
引入
用sklearn 中的sklearn.feature_extraction.text.TfidfTransformer 來獲取TF特征 ,但發(fā)現(xiàn)sklearn 的計算結果與我手工計算結果不一樣。雖然能在github上找到sklearn 的源碼。但不能動態(tài)調試,就無法直觀的看到結果。
那么問題來了,我們怎么樣才能動態(tài)調試Python的第三方庫(比如sklearn )呢?怎么樣才能看到第三方庫中源碼動態(tài)運行的中間結果?
假設我的代碼如下:
# 原始語料,3個文本
strs_train =[
'God is love',
'OpenGL on the GPU is fast',
'Doctor David is PHD']
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
# 先提取 Bags of words特征
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(strs_train)
# 再基于Bags of words特征,變換為TF特征
tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts)
X_train_tf = tf_transformer.transform(X_train_counts)
print(X_train_tf.todense())
我怎么樣才能看到函數(shù)sklearn.feature_extraction.text.TfidfTransformer.transform() 計算的中間結果呢?
Python調試基礎
Python 自帶了一個用于調試代碼的模塊pdb 。它支持斷點設置,單步調試,進入函數(shù)調試,查看代碼片段,查看變量值,動態(tài)改變變量值。
下面兩行代碼就能給程序加斷點:
import pdb
pdb.set_trace()
加了斷點,運行程序,當程序停下,就可以用下面幾個命令,在SHELL中調試代碼。
命令 |
含義 |
c |
繼續(xù)執(zhí)行代碼 |
n |
下一步 |
r |
執(zhí)行代碼,從當前函數(shù)返回 |
s |
進入函數(shù) |
b |
下斷點 |
調試Python第三方庫
我們用pdb ,就可以在第三方庫中下斷點,并進行調試。這里以調試sklearn 中的sklearn.feature_extraction.text.TfidfTransformer 為例,給出如下步驟。
先利用如下Python代碼找到sklearn 源碼位置。我的位置在C:\\Users\\biny\\Anaconda3\\lib\\site-packages\\sklearn 。
import sklearn, os
path = os.path.dirname(sklearn.__file__)
Python程序在運行時,為了提高運行速度,Python解釋器先將.py代碼 編譯為byte code (字節(jié)碼 ),再有Python虛擬機 來執(zhí)行字節(jié)碼。
下次再運行同一程序時,若.py代碼 沒有改變,則省略將.py代碼 編譯為字節(jié)碼 的步驟,直接運行上次已編譯好的字節(jié)碼 。
這些字節(jié)碼 ,會被存于__pycache__ 文件夾下,和.pyc文件 。按照原理,這個步驟是不需要做的,不過刪掉字節(jié)碼在運行自己的程序,如果不會出現(xiàn)新的字節(jié)碼文件,說明你的第三方庫位置找錯了。這樣能方便我們發(fā)現(xiàn)錯誤。
根據(jù)第三方庫的位置,找到sklearn.feature_extraction.text.TfidfTransformer.transform() 函數(shù)所在.py文件 。并用pdb 在函數(shù)開頭加上斷點(如下)。
def transform(self, X, copy=True):
import pdb
pdb.set_trace()
if hasattr(X, 'dtype') and np.issubdtype(X.dtype, np.float):
# preserve float family dtype
X = sp.csr_matrix(X, copy=copy)
else:
# convert counts or binary occurrences to floats
X = sp.csr_matrix(X, dtype=np.float64, copy=copy)
運行我的代碼,停在第三方庫中,就可以用pdb命令調試第三方代碼了。
此時代碼已經(jīng)運行并進入第三方庫中,停止在斷點處:
C:\mine\tmp\debug_py_3rd_lib>python main.py
c:\users\biny\anaconda3\lib\site-packages\sklearn\feature_extraction\text.py(1018)transform()
-> if hasattr(X, ‘dtype’) and np.issubdtype(X.dtype, np.float):
(Pdb)
用n命令(next),讓代碼單步運行到關鍵點:
c:\users\biny\anaconda3\lib\site-packages\sklearn\feature_extraction\text.py(1042)transform()
-> if self.norm:
(Pdb) n
直接輸入要查看的中間變量(X.data),停下的這行代碼是即將執(zhí)行的,我們可以看到執(zhí)行前的變量值:
c:\users\biny\anaconda3\lib\site-packages\sklearn\feature_extraction\text.py(1043)transform()
-> X = normalize(X, norm=self.norm, copy=False)
(Pdb) X.data
array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
繼續(xù)執(zhí)行代碼(n命令),然后可以看到中間變量值被改變。也能看到這個改變是因為做了normalize 。
(Pdb) n
c:\users\biny\anaconda3\lib\site-packages\sklearn\feature_extraction\text.py(1045)transform()
-> return X
(Pdb) X.data
array([ 0.57735027, 0.57735027, 0.57735027, 0.40824829, 0.40824829,
0.40824829, 0.40824829, 0.40824829, 0.40824829, 0.5 ,
0.5 , 0.5 , 0.5 ])
記住調試結束后,一定要在第三方源碼中刪掉pdb斷點那兩行代碼!
參考
|