目錄 | 上一節 (8.2 日誌) | 下一節 (9 包)
8.3 除錯
除錯建議
假設程式崩潰了:
bash % python3 blah.py
Traceback (most recent call last):
File "blah.py", line 13, in ?
foo()
File "blah.py", line 10, in foo
bar()
File "blah.py", line 7, in bar
spam()
File "blah.py", 4, in spam
line x.append(3)
AttributeError: 'int' object has no attribute 'append'
那麼現在該怎麼辦呢?
閱讀回溯資訊
最後一行是程式崩潰的具體原因:
bash % python3 blah.py
Traceback (most recent call last):
File "blah.py", line 13, in ?
foo()
File "blah.py", line 10, in foo
bar()
File "blah.py", line 7, in bar
spam()
File "blah.py", 4, in spam
line x.append(3)
# Cause of the crash
AttributeError: 'int' object has no attribute 'append'
不過,回溯資訊並不總是那麼易於閱讀或理解。
專業建議:將整個回溯貼上到谷歌。
使用互動式直譯器(REPL)
執行指令碼的 時候,可以使用選項 -i
使 Python 保持存活(keep alive)。
bash % python3 -i blah.py
Traceback (most recent call last):
File "blah.py", line 13, in ?
foo()
File "blah.py", line 10, in foo
bar()
File "blah.py", line 7, in bar
spam()
File "blah.py", 4, in spam
line x.append(3)
AttributeError: 'int' object has no attribute 'append'
>>>
選項 -i
可以保留直譯器狀態。這意味著可以在程式崩潰後查詢錯誤資訊。對變數的值和其它狀態進行檢查。
使用列印進行除錯
使用 print()
函式進行除錯非常常見。
建議:確保使用的是 repr()
函式。
def spam(x):
print('DEBUG:', repr(x))
...
repr()
函式顯示一個值的準確表示,而不是格式良好的輸出。
>>> from decimal import Decimal
>>> x = Decimal('3.4')
# NO `repr`
>>> print(x)
3.4
# WITH `repr`
>>> print(repr(x))
Decimal('3.4')
>>>
Python 的偵錯程式
可以在程式內手動啟動偵錯程式(debugger)。
def some_function():
...
breakpoint() # Enter the debugger (Python 3.7+)
...
上述操作會在 breakpoint()
呼叫時啟動偵錯程式。
在 Python 的早期版本中,可能會看到下面這樣的除錯指南:
import pdb
...
pdb.set_trace() # Instead of `breakpoint()`
...
(譯註:Python 3.7 之後,可以使用內建函式 breakpoint()
代替 import pdb; pdb.set_trace()
)
在除錯直譯器下執行程式
也可以在偵錯程式下執行整個程式:
bash % python3 -m pdb someprogram.py
上述操作會在第一行語句之前自動進入偵錯程式,允許設定斷點和修改配置。
常見的偵錯程式命令:
(Pdb) help # Get help
(Pdb) w(here) # Print stack trace
(Pdb) d(own) # Move down one stack level
(Pdb) u(p) # Move up one stack level
(Pdb) b(reak) loc # Set a breakpoint
(Pdb) s(tep) # Execute one instruction
(Pdb) c(ontinue) # Continue execution
(Pdb) l(ist) # List source code
(Pdb) a(rgs) # Print args of current function
(Pdb) !statement # Execute statement
斷點的位置可以用下列任意一種方式進行表示:
(Pdb) b 45 # Line 45 in current file
(Pdb) b file.py:45 # Line 34 in file.py
(Pdb) b foo # Function foo() in current file
(Pdb) b module.foo # Function foo() in a module
練習
練習 8.4:Bugs? 什麼是 Bugs?
有 bug,我們就解決 bug(It runs. Ship it!)。
目錄 | 上一節 (8.2 日誌) | 下一節 (9 包)