翻譯:《實用的Python編程》08_03_Debugging
- 2021 年 4 月 11 日
- 筆記
- Python, 實用的Python編程
目錄 | 上一節 (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'
不過,回溯資訊並不總是那麼易於閱讀或理解。
專業建議:將整個回溯粘貼到Google。
使用互動式解釋器(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 包)
註:完整翻譯見 //github.com/codists/practical-python-zh