|
注意:本文方法僅限于調(diào)試安裝時(shí)附帶py源碼的庫(kù),如sklearn。
引入
用sklearn中的sklearn.feature_extraction.text.TfidfTransformer來(lái)獲取TF特征,但發(fā)現(xiàn)sklearn的計(jì)算結(jié)果與我手工計(jì)算結(jié)果不一樣。雖然能在github上找到sklearn的源碼。但不能動(dòng)態(tài)調(diào)試,就無(wú)法直觀的看到結(jié)果。
那么問(wèn)題來(lái)了,我們?cè)趺礃硬拍軇?dòng)態(tài)調(diào)試Python的第三方庫(kù)(比如sklearn)呢?怎么樣才能看到第三方庫(kù)中源碼動(dòng)態(tài)運(yùn)行的中間結(jié)果?
假設(shè)我的代碼如下:
# 原始語(yǔ)料,3個(gè)文本
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()計(jì)算的中間結(jié)果呢?
Python調(diào)試基礎(chǔ)
Python自帶了一個(gè)用于調(diào)試代碼的模塊pdb。它支持?jǐn)帱c(diǎn)設(shè)置,單步調(diào)試,進(jìn)入函數(shù)調(diào)試,查看代碼片段,查看變量值,動(dòng)態(tài)改變變量值。
下面兩行代碼就能給程序加斷點(diǎn):
import pdb
pdb.set_trace()
加了斷點(diǎn),運(yùn)行程序,當(dāng)程序停下,就可以用下面幾個(gè)命令,在SHELL中調(diào)試代碼。
| 命令 |
含義 |
| c |
繼續(xù)執(zhí)行代碼 |
| n |
下一步 |
| r |
執(zhí)行代碼,從當(dāng)前函數(shù)返回 |
| s |
進(jìn)入函數(shù) |
| b |
下斷點(diǎn) |
調(diào)試Python第三方庫(kù)
我們用pdb,就可以在第三方庫(kù)中下斷點(diǎn),并進(jìn)行調(diào)試。這里以調(diào)試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__)
- (2)刪掉Python預(yù)編譯的
字節(jié)碼
Python程序在運(yùn)行時(shí),為了提高運(yùn)行速度,Python解釋器先將.py代碼編譯為byte code(字節(jié)碼),再有Python虛擬機(jī)來(lái)執(zhí)行字節(jié)碼。
下次再運(yùn)行同一程序時(shí),若.py代碼沒(méi)有改變,則省略將.py代碼編譯為字節(jié)碼的步驟,直接運(yùn)行上次已編譯好的字節(jié)碼。
這些字節(jié)碼,會(huì)被存于__pycache__文件夾下,和.pyc文件。按照原理,這個(gè)步驟是不需要做的,不過(guò)刪掉字節(jié)碼在運(yùn)行自己的程序,如果不會(huì)出現(xiàn)新的字節(jié)碼文件,說(shuō)明你的第三方庫(kù)位置找錯(cuò)了。這樣能方便我們發(fā)現(xiàn)錯(cuò)誤。
根據(jù)第三方庫(kù)的位置,找到sklearn.feature_extraction.text.TfidfTransformer.transform()函數(shù)所在.py文件。并用pdb在函數(shù)開(kāi)頭加上斷點(diǎn)(如下)。
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)
運(yùn)行我的代碼,停在第三方庫(kù)中,就可以用pdb命令調(diào)試第三方代碼了。
此時(shí)代碼已經(jīng)運(yùn)行并進(jìn)入第三方庫(kù)中,停止在斷點(diǎn)處:
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),讓代碼單步運(yùn)行到關(guān)鍵點(diǎn):
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命令),然后可以看到中間變量值被改變。也能看到這個(gè)改變是因?yàn)樽隽?code>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 ])
記住調(diào)試結(jié)束后,一定要在第三方源碼中刪掉pdb斷點(diǎn)那兩行代碼!
參考
|