做一手房用什么網(wǎng)站百度競(jìng)價(jià)開戶需要多少錢
一、問(wèn)題概述
回調(diào)函數(shù)是指一個(gè)函數(shù)執(zhí)行完后,調(diào)用另外一個(gè)函數(shù)的過(guò)程。
一般步驟是,回調(diào)函數(shù)作為參數(shù)傳遞給原始函數(shù),原始函數(shù)執(zhí)行完自己的邏輯后,自動(dòng)調(diào)用回調(diào)函數(shù)并將自己的執(zhí)行結(jié)果作為參數(shù)傳遞給回調(diào)函數(shù)。
根據(jù)不同的用法,回調(diào)函數(shù)可能在主線程/進(jìn)程中,也可能在其他線程/進(jìn)程中。有時(shí)候,這會(huì)給調(diào)試回調(diào)函數(shù)帶來(lái)一點(diǎn)麻煩,比如,在回調(diào)函數(shù)內(nèi)打的斷點(diǎn),在調(diào)試模式下死活無(wú)法觸發(fā)。(是的,在pycharm中遇到這個(gè)情況的就是我。。。)
這時(shí),為了能正常調(diào)試,可以考慮以下方法:
1、如果回調(diào)函數(shù)是普通函數(shù),或者普通的類,可以先不作為回調(diào)函數(shù)使用,而是先當(dāng)成普通函數(shù)來(lái)正常調(diào)試,確認(rèn)其中的邏輯沒問(wèn)題, 再按回調(diào)函數(shù)的用法來(lái)調(diào)用。
2、不使用 pycharm 中內(nèi)置的調(diào)試功能,使用 ipdb(window) 或者 pudb(linux)來(lái)調(diào)試。
第1點(diǎn)比較簡(jiǎn)單,以下介紹一下第 2 點(diǎn)中如何使用 ipdb 來(lái)調(diào)試回調(diào)函數(shù)。
二、ipdb 調(diào)試回調(diào)函數(shù)
1、ipdb是什么
pdb(python debugger)是一個(gè)集成于Python標(biāo)準(zhǔn)庫(kù)中的交互式無(wú)界面調(diào)試工具,功能主要包括:
a、斷點(diǎn)設(shè)置與跳轉(zhuǎn)
b、單步執(zhí)行代碼
c、任意變量查詢、值修改(不必重啟程序)
pdb 的弱點(diǎn)在于對(duì)多線程,遠(yuǎn)程調(diào)試等支持得不夠好,沒有界面,不太適合大型的 python 項(xiàng)目。
ipdb是增強(qiáng)版的pdb,它提供了更多的功能和更友好的交互界面,使得在開發(fā)過(guò)程中調(diào)試代碼變得更加方便。 功能包括:
a、在代碼中的任意位置設(shè)置斷點(diǎn)
b、單步運(yùn)行語(yǔ)句,并查看其結(jié)果
c、可查看當(dāng)前執(zhí)行上下文中的變量值
d、可跳過(guò)某個(gè)函數(shù)或循環(huán)
e、命令行界面
f、語(yǔ)法tab補(bǔ)全、條件斷點(diǎn)、彩色輸出等
2、ipdb的安裝與常用命令簡(jiǎn)介
2.1、安裝
pip install ipdb
2.2、常用命令簡(jiǎn)介
! 執(zhí)行 python 命令,或者顯示變量值
ENTER 重復(fù)上次命令
a(rgs) 打印當(dāng)前函數(shù)的參數(shù)
b(reakpoint) 設(shè)置斷點(diǎn)
cl(ear) 清除斷點(diǎn)
c(ontinue) 運(yùn)行直到斷點(diǎn)位置
h(elp) 幫助信息
j(ump) 讓程序跳轉(zhuǎn)到指定的行數(shù)
l(ist) 列出想了解的代碼,查找當(dāng)前位置
n(ext) 讓程序運(yùn)行下一行,當(dāng)前語(yǔ)句有函數(shù)/子程序調(diào)用也不進(jìn)入
s(tep) 讓程序運(yùn)行下一行,當(dāng)前語(yǔ)句有函數(shù)/子程序就進(jìn)入
p(rint) 打印某個(gè)變量
q(uit) 退出調(diào)試
r(eturn) 繼續(xù)執(zhí)行,直到函數(shù)體返回
disable/enable 禁用/啟用斷點(diǎn)
3、ipdb的啟動(dòng)
假設(shè) d:\download\callback_debug.py 需要調(diào)試。有兩種方式能夠?qū)λM(jìn)行調(diào)試:
3.1、在IDE中啟動(dòng)
a、在代碼中導(dǎo)入 ipdb 的 set_trace
b、在要調(diào)試的行之前插入 set_trace()
c、運(yùn)行代碼,則代碼自動(dòng)在 set_trace() 處停止,等待調(diào)試
3.2、在命令行啟動(dòng)
python -m ipdb d:/download/callback_debug.py
方法 3.1 在IDE中執(zhí)行,會(huì)修改源碼,并且對(duì)循環(huán)等的調(diào)試支持不是很好,相對(duì)來(lái)說(shuō),方法 3.2 更加靈活一些,但是對(duì)多線程、多進(jìn)程的場(chǎng)景,按方法 3.2,非主進(jìn)程、主線程上的斷點(diǎn)不一定能抓住。
以下主要討論方法 3.2,但是使用方法也適用于 3.1。
4、舉例:以一個(gè)調(diào)試過(guò)程為例
4.0、原始代碼
def on_callback(num, num2):a = 1b = '這是一串字符'if num == 3:print('haha')print(f"回調(diào)處理后的數(shù)字是 {num} * {num} = {num * num}")def foo(num, callback: callable):print(f"當(dāng)前的數(shù)字是:{num}")callback(num, 10)if __name__ == '__main__':for i in range(5):foo(i, on_callback)
4.1、命令行啟動(dòng) ipdb
(base) D:\xxxx\trial>python -m ipdb callback_debug.py
# 執(zhí)行結(jié)果為:
> d:\xxxx\trial\callback_debug.py(1)<module>()
----> 1 def on_callback(num):2 if num == 3:3 print('haha')ipdb>
此時(shí)自動(dòng)進(jìn)入單步執(zhí)行狀態(tài),ipdb 停留在第一行代碼處待命。
4.2、查看代碼
查看第1行至第10行的代碼內(nèi)容(沒有第0行)
ipdb> l 1,10
----> 1 def on_callback(num):2 if num == 3:3 print('haha')4 print(f"回調(diào)處理后的數(shù)字是 {num} * {num} = {num * num}")5 6 7 def foo(num, callback: callable):8 print(f"當(dāng)前的數(shù)字是:{num}")9 callback(num)10 ipdb>
ll 是查看整個(gè)源碼文件
4.3、設(shè)置斷點(diǎn)
在 on_callback() 函數(shù)內(nèi)設(shè)置斷點(diǎn),位置是第4、11行,分別在回調(diào)函數(shù)、初始函數(shù)內(nèi)。
ipdb> b 4
Breakpoint 1 at d:\xxxx\trial\callback_debug.py:4
ipdb> b 11
Breakpoint 2 at d:\xxxx\trial\callback_debug.py:11
ipdb>
4.4、運(yùn)行至斷點(diǎn)處
斷點(diǎn)2后設(shè)置,但是運(yùn)行邏輯上先運(yùn)行到。
ipdb> c
當(dāng)前的數(shù)字是:0
> d:\xxxx\trial\callback_debug.py(11)foo()10 print(f"當(dāng)前的數(shù)字是:{num}")
2--> 11 callback(num, 10)12 ipdb>
4.5、在函數(shù) foo 里,查看都有哪些參數(shù)
ipdb> a
num = 0
callback = <function on_callback at 0x0000010B5C856940>
ipdb>
4.6、進(jìn)入回調(diào)函數(shù)內(nèi)部
ipdb> s
--Call--
> d:\xxxx\trial\callback_debug.py(1)on_callback()
----> 1 def on_callback(num, num2):2 a = 13 b = '這是一串字符'ipdb>
4.7、連續(xù)單步運(yùn)行
其中第一次單步執(zhí)行需要輸入 n 后再回車,之后2次直接回車即可
ipdb> n
> d:\xxxx\trial\callback_debug.py(2)on_callback()1 def on_callback(num, num2):
----> 2 a = 13 b = '這是一串字符'ipdb>
> d:\xxxx\trial\callback_debug.py(3)on_callback()2 a = 1
----> 3 b = '這是一串字符'
1 4 if num == 3:ipdb>
> d:\xxxx\trial\callback_debug.py(4)on_callback()3 b = '這是一串字符'
1---> 4 if num == 3:5 print('haha')ipdb>
4.8、跳出、跳入回調(diào)函數(shù),并查看入?yún)⑴c變量值
ipdb> u
> d:\xxxx\trial\callback_debug.py(11)foo()10 print(f"當(dāng)前的數(shù)字是:{num}")
2--> 11 callback(num, 10)12 ipdb> d
> d:\xxxx\trial\callback_debug.py(4)on_callback()3 b = '這是一串字符'
1---> 4 if num == 3:5 print('haha')ipdb> args
num = 0
num2 = 10
ipdb>p num
2
ipdb> num
2
ipdb>
4.9、跳轉(zhuǎn)到指定行(必須與跳轉(zhuǎn)之前位置在同一個(gè)函數(shù)內(nèi))
> d:\xxxx\trial\callback_debug.py(2)on_callback()1 def on_callback(num, num2):
----> 2 a = 13 b = '這是一串字符'ipdb> j 4
> d:\xxxx\trial\callback_debug.py(4)on_callback()3 b = '這是一串字符'
1---> 4 if num == 3:5 print('haha')ipdb>
4.10、取消第一個(gè)斷點(diǎn)并執(zhí)行代碼至第2個(gè)斷點(diǎn)處
ipdb> cl 1
Deleted breakpoint 1 at d:\xxxx\trial\callback_debug.py:4
ipdb> c
當(dāng)前的數(shù)字是:2
> d:\xxxx\trial\callback_debug.py(11)foo()10 print(f"當(dāng)前的數(shù)字是:{num}")
2--> 11 callback(num, 10)12 ipdb>
4.11、顯示當(dāng)前所處的位置以及堆棧信息
ipdb> wd:\anaconda3\lib\bdb.py(580)run()579 try:
--> 580 exec(cmd, globals, locals)581 except BdbQuit:<string>(1)<module>()d:\xxxx\trial\callback_debug.py(16)<module>()14 if __name__ == '__main__':15 for i in range(5):
---> 16 foo(i, on_callback)> d:\xxxx\trial\callback_debug.py(11)foo()10 print(f"當(dāng)前的數(shù)字是:{num}")
2--> 11 callback(num, 10)12ipdb>
4.12、退出調(diào)試
ipdb> q(base) D:\xxxx\trial>
三、參考資料
1、pdb調(diào)試神器使用終極指南
2、pytorch Debug —交互式調(diào)試工具Pdb (ipdb是增強(qiáng)版的pdb)-1-使用說(shuō)明