調(diào)試你的Python代碼
調(diào)試你的Python代碼
譯自: http://howchoo.com/g/zgi2y2iwyze/debugging-your-Python-code
作者: Ashley
當(dāng)你不得不更新別人的代碼時,你有多少次陷入這樣一種境地?如果你是一個開發(fā)團(tuán)隊的一員,那我猜一定多于你愿意的次數(shù)。 結(jié)果我們發(fā)現(xiàn)Python (和其他語言一樣)提供了在這種情況下便利的debug特性。愿這份快速指南能使你的生活輕松些。
1 一段糟糕的代碼
出于本教程段目的讓我們假設(shè)如下一段簡單段程序。這段程序獲取兩個命令行參數(shù)以及加減操作。 (讓我們假設(shè)用戶輸入的參數(shù)無誤,因此無需處理異常)
import sys def add(num1=0, num2=0): return int(num1) + int(num2) def sub(num1=0, num2=0): return int(num1) - int(num2) def main(): #Assuming our inputs are valid numbers print sys.argv addition = add(sys.argv[1], sys.argv[2]) print addition subtraction = sub(sys.argv[1], sys.argv[2]) print subtraction if __name__ == '__main__': main()
2 加入pdb
Python自帶了名為pdb的,基于交互的源碼debug模塊。
你需要已如下方式啟用該模塊。
import pdb pdb.set_trace()
加入斷點(diǎn)(break points) 的示例程序:
import pdb import sys def add(num1=0, num2=0): return int(num1) + int(num2) def sub(num1=0, num2=0): return int(num1) - int(num2) def main(): #Assuming our inputs are valid numbers print sys.argv pdb.set_trace() # <-- Break point added here addition = add(sys.argv[1], sys.argv[2]) print addition subtraction = sub(sys.argv[1], sys.argv[2]) print subtraction if __name__ == '__main__': main()
# /Users/someuser/debugger.py(15)main() -> addition = add(sys.argv[1], sys.argv[2]) (Pdb)
我們會看到下次被執(zhí)行的將是第15行。
程序在執(zhí)行第15行前暫停了。
我們在這里有一些選擇。。。讓我們在接下來的步驟中展示其中一部分。
4 下一行 -> n
在debugger提示符處 按"n" 會到下一行。
> /Users/someuser/debugger.py(14)main() -> addition = add(sys.argv[1], sys.argv[2]) (Pdb) n > /Users/someuser/debugger.py(15)main() -> print addition
這會執(zhí)行當(dāng)前行并準(zhǔn)備好執(zhí)行下一行。
我們雖然能夠通過使用"n" 來一行行執(zhí)行程序,但這樣不是太有用。
你可能已經(jīng)注意到了pdb實(shí)際上并沒有進(jìn)入add函數(shù)中。讓我們在看看debugger的其他選項,使排錯變得更有趣。
注意:
另一個酷酷的特性是按回車鍵會執(zhí)行你之前執(zhí)行過的命令(本例中為"n")。
5 打印 ->p
讓我們再次開始debug吧?。热晃覀儧]有任何程序會執(zhí)行完。你可以敲擊"c"使pdb跳至最后或者下一個斷點(diǎn)(break point)
['debugger.py', '1', '2'] > /Users/someuser/debugger.py(14)main() -> addition = add(sys.argv[1], sys.argv[2]) (Pdb)
現(xiàn)在如果我們想知道sys.argv包含了哪些參數(shù),我們可以這么干:
-> addition = add(sys.argv[1], sys.argv[2]) (Pdb) p sys.argv ['debugger.py', '1', '2'] (Pdb) p sys.argv[1] '1' (Pdb)
這在檢測變量實(shí)際存儲的值時非常有用。
現(xiàn)在讓我們進(jìn)入add函數(shù)內(nèi)部
6 進(jìn)入函數(shù) -> s
我們可以通過使用"s"來進(jìn)入我們的addition函數(shù)。
(Pdb) s --Call-- > /Users/someuser/debugger.py(4)add() -> def add(num1=0, num2=0): (Pdb) n > /Users/someuser/debugger.py(5)add() -> return int(num1) + int(num2) (Pdb)
這使我們來到了add函數(shù)的內(nèi)部,現(xiàn)在我們能夠在其中使用"n, p"以及其他操作了。
這時敲擊"r"會跳轉(zhuǎn)至所進(jìn)入函數(shù)的返回語句處。(譯注:再次敲擊時會跳轉(zhuǎn)至函數(shù)調(diào)用處)
這在你想快速跳轉(zhuǎn)至方法結(jié)尾時很有用。
7 動態(tài)添加斷點(diǎn)(break point) -> b
我們在運(yùn)行程序前通過pdb.set_trace()設(shè)置了斷點(diǎn)(break point)
通常在debugger開始后,我們會想在一些特定的位置設(shè)置斷點(diǎn)(break point)
好基友 "b" 登場。
讓我們再次執(zhí)行我們的程序
['debugger.py', '1', '2'] > /Users/someuser/debugger.py(15)main() -> addition = add(sys.argv[1], sys.argv[2]) (Pdb)
現(xiàn)在我在第18行設(shè)置一個斷點(diǎn)(break point)。
-> addition = add(sys.argv[1], sys.argv[2]) (Pdb) b 18 Breakpoint 1 at /Users/someuser/debugger.py:18 (Pdb) c We are in add-- 3 > /Users/someuser/debugger.py(18)main() -> print subtraction (Pdb) p subtraction -1 (Pdb)
如我們所見,pdb直接跳至第18行并等待進(jìn)一步指令。
pdb也會給斷點(diǎn)賦一個數(shù)字(本例中為數(shù)字1)。我們能夠使用(原文為"user" 疑似筆誤)
enable/disable 斷點(diǎn)(break point)數(shù)字再進(jìn)一步執(zhí)行中啟用或關(guān)閉相對應(yīng)的斷點(diǎn)(break point)。
8 列表 -> l
有時在debug的過程中,你會迷失于代碼中。此時,你可以使用"l"來輸出一個格式良好的摘要來告知你你身在何處。# 斟酌
['debugger.py', '1', '2'] > /Users/someuser/debugger.py(15)main() -> addition = add(sys.argv[1], sys.argv[2]) (Pdb) l 10 11 def main(): 12 #Assuming our inputs are valid numbers 13 print sys.argv 14 pdb.set_trace() # <-- Break point added here 15 -> addition = add(sys.argv[1], sys.argv[2]) 16 print addition 17 subtraction = sub(sys.argv[1], sys.argv[2]) 18 print subtraction
9 給變量動態(tài)賦值
在debug時,能給變量賦值也有助于排錯。
假設(shè):
['debugger.py', '1', '2'] > /Users/someuser/debugger.py(15)main() -> addition = add(sys.argv[1], sys.argv[2]) (Pdb) n We are in add-- > /Users/someuser/debugger.py(16)main() -> print addition (Pdb) p addition 3 #<--- addition here is 3 (Pdb) addition = 'this is now string' #<--- We changed the value of additon (Pdb) n this is now string #<--- Now when we print it we actually gets it as a string. that we just set above. > /Users/someuser/debugger.py(17)main() -> subtraction = sub(sys.argv[1], sys.argv[2])
注意:
如果你想給像"n"這樣的變量賦值(即同時也是pdb 命令),你需要這樣做:
(Pdb) !n=5 (Pdb) p n 5
10 退出 -> q
最后你可以通過"q",在任何時刻退出。程序執(zhí)行會被終止。
11 擴(kuò)展閱讀
本文僅僅觸及pdb的表面。還有更多的文檔在向你招手!
那些使用iPython的能夠在ipdb中找到更好的debugger:tab補(bǔ)全,語法高亮以及其他酷酷的特性。
如果你有其他使用pdb的有趣方法請在下面評論
排錯愉快!