Python Note 04
Python的Debug神器
在日常除錯過程中,我們經常會使用 print()
函數查看變數內容,以確認程式執行的結果是否如預期。然而,這樣做往往需要花費大量時間去逐一檢查輸出的正確性。在 Python 中,有一個內建函數叫做 breakpoint()
,專門用於啟動偵錯器。當執行到 breakpoint()
時,程序會暫停,並進入一個互動式的調試環境。透過這個功能,你可以查看變數的值、逐步執行程式碼,以及有效地進行問題調試。
breakpoint()
的主要功能:
- 暫停程序執行:當程式執行到
breakpoint()
時,程式會暫停,進入偵錯器。 - 進入互動式調試環境:你可以查看目前的變數、執行下一步操作、檢查堆疊幀等。
- 調試程式碼:你可以使用偵錯器的命令(例如
n
進入下一步、c
繼續運行、q
退出調試器等)來逐步執行程式碼,幫助你發現問題。
breakpoint()
在Python 3.7 版本中被引入,它會調用sys.breakpointhook()
,通常會啟動預設的Python 偵錯器pdb
。
常見調試器命令:
n
(next):執行下一行程式碼。s
(step):執行下一行程式碼,如果該行為函數呼叫則進入函數,停在函數第一行。w
(where):列出從當前執行點到最外層調用的一系列函數調用和行號。c
(continue):繼續執行直到遇到下一個斷點或程式結束。q
(quit):退出偵錯器並結束程式。p
(print):列印變數的值,例如p some_variable
。l
(list):印出目前所在 function/frame上下 10 行的程式碼。ll
(long list):印出目前所在 function/frame 的所有程式碼。r
(return):繼續執行到當前函數返回為止。
使用breakpoint()
的範例:
運行範例:
def calculate_area(length, width):
area = length * width
breakpoint()
return area
length = 5
width = 10
area = calculate_area(length, width)
print(f"The area is {area}")
當程式碼執行到breakpoint()
時,會進入偵錯模式,你可以使用偵錯器指令來查看變數的值或逐步執行程式碼。
輸出(在進入調試模式後):
> <filename>(5)calculate_area()
-> return area
(Pdb) p length
5
(Pdb) p width
10
(Pdb) p area
50
(Pdb) n
(Pdb) w
/media/lukaslu/2E7C3ACF7C3A9217/user_data/Jim/code/MongoDB_MinIO_FastAPI/test.py(8)<module>()
-> area = calculate_area(length, width)
> /media/lukaslu/2E7C3ACF7C3A9217/user_data/Jim/code/MongoDB_MinIO_FastAPI/test.py(4)calculate_area()
-> return area
在這個範例中,程式會在breakpoint()
處暫停,你可以使用p
指令查看變數length
、width
和area
的值;使用n
逐步執行程式碼;使用w
可以查看從程式入口到當前中斷點的完整調用棧,箭頭 ->
指向當前正在執行的行。
小技巧
使用 breakpoint()
的一些小技巧可以讓你的 Python 調試過程更加高效和便利。以下是一些實用的建議:
條件斷點
你可以在 breakpoint()
函數中添加條件,只有當條件為真時,才會觸發斷點。這在處理循環或條件語句中特別有用。
for i in range(100):
if i == 50:
breakpoint() # 只在 i 等於 50 時暫停
動態設置和移除斷點
通過編程方式設置和移除斷點,可以根據運行時數據或條件動態地改變調試策略。
if some_condition:
breakpoint() # 動態設置斷點
整合日誌
使用 breakpoint()
時,考慮在進入調試器前後添加日誌語句,這樣可以在不進入調試器的情況下追蹤程式的運行狀態。
logging.debug('About to hit breakpoint')
breakpoint()
logging.debug('Resuming from breakpoint')
自定義 sys.breakpointhook
你可以自定義 breakpoint()
的行為,通過設置 sys.breakpointhook
。這允許你在觸發斷點時執行自定義代碼或調用其他調試器,如 ipdb
,提供了 pdb
的所有功能,同時增加了語法高亮、Tab 補全和更詳細的調用棧資訊,使得調試過程更直觀和用戶友好。提
import sys
def my_debugger():
import ipdb
print("Custom debugging session starts.")
ipdb.set_trace()
sys.breakpointhook = my_debugger
# Somewhere in your code
breakpoint() # This will trigger `my_debugger` instead of the default pdb.
進行性能分析
在性能關鍵部分的代碼中使用breakpoint()
,檢查特定操作前後的系統狀態或變數,使用如 memory_profiler
或 time
模塊來檢測記憶體使用或時間消耗,有助於識別效能瓶頸。
from memory_profiler import memory_usage
import time
import pdb
def perform_heavy_operations():
# 假設這是一個記憶體和處理時間密集型操作
sum = 0
for i in range(10000000):
sum += i
return sum
# 檢測記憶體和時間使用
initial_memory = memory_usage()
start_time = time.time()
# 執行密集型操作
result = perform_heavy_operations()
# 斷點設置
breakpoint() # 在此處觸發斷點以檢視當前狀態
final_memory = memory_usage()
end_time = time.time()
# 計算使用的記憶體和時間
memory_used = final_memory[0] - initial_memory[0] # 單位為 MiB
time_taken = end_time - start_time # 單位為秒
print(f"Result of operations: {result}")
print(f"Memory used: {memory_used} MiB")
print(f"Time taken: {time_taken} seconds")
總結
breakpoint()
的基本功能:
- 暫停程序執行:在指定的代碼點暫停執行,進入偵錯模式。
- 互動式調試環境:允許查看變數、逐步執行程式碼、檢查調用棧等。
- 簡化調試過程:提供一個直觀的方式來逐步通過程式碼,找出錯誤的來源。
breakpoint()
使用技巧:
- 條件斷點:在符合特定條件時才觸發斷點,適用於循環或條件語句中。
- 動態斷點:根據運行時數據或條件動態設置斷點,以靈活調整調試策略。
- 整合日誌:在進入和離開調試器時記錄日誌,方便追蹤程式運行狀態。
- 自定義
sys.breakpointhook
:自定義斷點行為,可整合其他工具或執行特定調試代碼。
使用 breakpoint()
進行性能分析:
- 檢測記憶體和時間使用:使用
memory_profiler
和time
模塊在斷點前後測量記憶體和執行時間,以識別效能瓶頸。 - 分析操作效果:透過斷點檢視特定操作對系統資源的影響,並評估優化策略。
這些總結點幫助你更有效地利用 breakpoint()
來進行錯誤排查和性能分析,提升開發效率和程式的運行效能。