隨著B端業務快速發展,系統愈趨複雜。我們發起了B端架構升級專項,基於B端業務的特點,從研發規範建設、B端架構基建、系統架構升級和落地保障等多方面提升了B端的架構水平 ...
5 調試
當運行程式時終端輸出錯誤時,可以參考編輯器中的"問題"面板來解決遇到的問題。不過,並非所有錯誤都會導致錯誤。可能出現的情況是,程式執行成功,但輸出結果與預期不同。出現這種情況時,下一步就是找出程式中的錯誤。這個過程被稱為調試。
您可以嘗試通過註釋代碼行(從而禁止代碼塊運行)、添加更多列印語句以在代碼塊執行後輸出,或修改程式中的行來定位和解決問題。雖然每種方法都能幫助你找出錯誤和可能的修複方法,但這一過程效率很低。
Visual Studio Code有內置調試器,它的功能通過Python擴展得到了進一步擴展。雖然調試器可以幫助您識別和修複錯誤,但您仍有責任識別錯誤可能出現在代碼的哪個位置。一旦你確定了錯誤的潛在位置,就可以使用調試器來幫助你跟蹤程式的執行狀態。
5.1 啟動調試
要讓調試器在執行過程中暫停,必須在代碼的某一行設置斷點。只要你想檢查程式的運行狀態,然後逐行檢查代碼,就可以設置斷點。在 Visual Studio 代碼中,斷點會以紅點的形式出現在編輯器空白處。當調試會話開始時,調試器會執行到斷點為止的所有代碼行,並高亮顯示要執行的下一行。(如果是步進操作,則例外,這將在後面的 "調試命令 "一節中解釋)。
要添加斷點,請將滑鼠懸停在當前代碼行的編輯器邊框上,然後單擊以添加斷點。或者,使用鍵盤快捷鍵F9來添加當前代碼行。要移除斷點,請在編輯器空白處選擇斷點,或再次按F9鍵。也可以在頂部菜單中選擇運行,然後選擇移除所有斷點,從而移除所有斷點。
你可以在會話期間暫停調試器的任何位置調用debugypy.breakpoint()來強制設置斷點。如果要強制設置斷點,必須在代碼中導入debuypy。調用後,調試器會停止下一行代碼。這種方法會在程式中硬編碼斷點。如果你有一些非同步的回調函數,而你又不想用其他斷點來設置、清除、啟用或禁用它們,那麼這種方法可能會很有用。通過對幾個斷點進行硬編碼,就能在回調函數發生時捕捉到它們。
您可以通過以下方式啟動調試會話:
- 菜單: 選擇運行 ➪ 啟動調試。
- 鍵盤快捷鍵: 按 F5。
- 運行視圖: 單擊運行和調試
- 運行視圖: 單擊 "開始調試"(在調試會話啟動後出現)
編輯器在調試會話期間的行為由調試配置控制。調試配置是調試器功能的設置列表。Python 擴展提供了幾種配置,稍後將在 "啟動配置 "中探討。本章練習中出現提示時,點擊 Python 文件配置,調試當前活動的 Python 文件。
啟動調試會話後,會打開運行視圖。運行視圖用於管理調試會話。當調試會話處於活動狀態時,"運行 視圖中的面板會根據正在執行的內容動態變化。
當代碼中添加斷點時,斷點面板會將模塊名稱(如times_two.py)及其相應的斷點行添加到列表中。目前times_two.py 中有兩個斷點,一個在第4行,另一個在第6行。在斷點面板中選擇其中一個斷點,編輯器就會高亮顯示該斷點。
假設你在程式中設置了多個斷點。在調試時,你決定在會話中只選擇一些斷點,這樣就不必在每個斷點都暫停調試器了。移除不需要的斷點會刪除斷點,如果你打算在後續調試會話中保留斷點,這可能不是你的本意。相反,你可以禁用斷點。在 "斷點"面板中,取消選中斷點旁邊的方框即可禁用斷點。或者,你也可以右鍵單擊斷點,然後單擊禁用斷點。如果想一次性禁用所有斷點,可以單擊"停用斷點"按鈕。不過,如果您想刪除所有斷點,請單擊"刪除斷點"按鈕。刪除所有斷點有助於確保清除程式中設置的所有斷點。
調試器運行時,變數的當前狀態會反映在變數面板中。變數面板將變數分為局部和全局範圍。
在繼續調試的過程中,請註意麵板中變數的變化情況。雖然變數會隨著程式的執行而填充,但變數值有可能會產生錯誤,從而導致代碼停止執行。如果你發現換一個值就能繼續執行程式,你可以在變數面板中更改該值。要更改數值,請選中變數並按Enter鍵。輸入新變數後,再按一次Enter鍵,將修改後的值保存到程式狀態中。
5.2 調試命令
除運行視圖外,編輯器中還會出現調試工具欄(見圖 5.9)。調試工具欄提供了對這些調試命令的快速訪問:
- A—Continue (F5)
- B—Step Over (F10)
- C—Step Into (F11)
- D—Step Out (Shift+F11)
- E—Restart (Shift+Cmd/Ctrl+F5)
- F—Stop (Shift+F5)
調試命令是一起工作的,而不是獨立的;也就是說,你通常要使用多種命令的組合來調試不同的代碼行。
除調試工具欄命令外,編輯器右鍵上下文菜單中還提供了其他命令。這些功能包括
- 添加內聯斷點(Add Inline Breakpoint)-在代碼中添加斷點,特別是在游標下的代碼中。這對單個語句中的複合表達式非常有用,因為您希望在表達式的特定部分斷開。或者,您可以導航到運行 ➪ 新斷點 ➪ 內聯斷點,或者使用鍵盤快捷鍵 Shift+F9。
- 運行到游標(Run to Cursor)-運行一段代碼而不設置另一個斷點。
- 跳轉到游標(Jump to Cursor)-跳轉代碼行或返回並重覆代碼行。
5.2.1 Continue
當調試器停在某個斷點時,單擊"繼續(Continue)"會運行該斷點後的所有代碼,直到下一個斷點或程式結束。
5.2.2 Step Over
Step Over命令運行調試器當前暫停的代碼行,然後自動暫停到下一行,無需另設斷點。如果當前行是函數調用,調試器將運行整個函數,然後在函數調用後的下一行暫停。從本質上講,Step Over命令是在當前範圍內逐行進行調試。
試試看 運行調試器,逐行查看代碼。註意,當調試器運行到 times_two() 函數定義處時,調試器的下一步是 print() 語句。
5.2.3 Step Into
當調試器在函數處暫停時,Step Into 命令會進入函數作用域。在這裡,你可以查看函數作用域內的每一行,還能進入其他函數調用。
5.2.4 Step Out
如果發現自己想從函數內部退出到調用該函數的作用域,可以使用Step Out命令。
5.2.5 停止
在調試會話期間,可以使用Stop命令停止所有執行。停止會話會停止調試器,但不會結束程式。如果在調試會話期間發現了程式中的錯誤,並得出結論:如果繼續執行,可能會產生影響程式的副作用,例如覆蓋錯誤的文件。在這種情況下,請選擇停止命令退出調試器。
5.2.5 重新啟動
在調試和糾正程式中的錯誤時,你往往不想繼續在當前(通常是錯誤的)狀態下運行程式。這時,你需要停止執行並重新啟動調試程式。重啟(Restart)命令可以方便地停止調試器,保存當前文件,然後用最近的修改重新啟動調試器。
參考資料
- 軟體測試精品書籍文檔下載持續更新 https://github.com/china-testing/python-testing-examples 請點贊,謝謝!
- 本文涉及的python測試開發庫 謝謝點贊! https://github.com/china-testing/python_cn_resouce
- python精品書籍下載 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
- Linux精品書籍下載 https://www.cnblogs.com/testing-/p/17438558.html
5.3 調用堆棧
模塊及其函數調用被稱為框架。幀相互堆疊,當函數返回時,相應的幀會從堆棧中清除。以times_two.py程式為例,模塊框架位於棧的底部,而times_two()函數框架位於棧的頂部。如果times_two()函數進行函數調用,被調用的函數將位於棧頂。調用棧本身被稱為調用棧。
調試視圖中的調用棧面板顯示了導致當前執行點的整個函數調用鏈。調用棧面板列出了正在調試的文件和文件中正在運行的行。如果調用經過項目中的其他文件,調用堆棧尤其有用,因為調用堆棧會記錄你在調試鏈中的位置。
此外,如果處於斷點處,可以選擇調用堆棧中的某一幀,變數面板會顯示堆棧中該斷點處的程式狀態。這對於通過堆棧和生成該值的所有代碼追溯錯誤值的源頭非常有用。
逐行查看代碼,直到調用times_two()函數。進入函數並註意調用堆棧。現在,times_two()框架已添加到調用堆棧中
調試器完成函數調用並返回總數後,times_two()框架將從調用棧面板中清除。
5.4 條件斷點(Logpoints)
你可以配置斷點,使其在特定條件為真時觸發(條件斷點),或在斷點被觸發一定次數後觸發。
當你為斷點指定的表達式求值為真時,條件斷點就會斷開。例如,如果要調試資料庫中的數據,可以在出現特定記錄時中斷。
命中計數使調試器能夠執行到指定的出現次數。Python擴展支持的命中計數是前面帶有 、>、>=、<、<= 和 % 操作符的整數。參考資料庫示例,假設您發現一個錯誤在進程的第 1500 次迭代時發生。與其每次迭代都進行到第 1500 次,不如設置當 1500 時斷開。
要添加條件斷點,請右鍵單擊相應行的編輯器邊距,然後單擊添加條件斷點。在出現的下拉菜單中,也可以使用相同的下拉菜單添加命中計數。
5.4 日誌點(Logpoints)
日誌點會向調試控制台輸出一條信息,而不會中斷調試器。日誌點在編輯器空白處顯示為菱形。
要添加日誌點,右鍵單擊相應行的編輯器頁邊空白處,然後單擊添加日誌點。雖然日誌信息是純文本,但也可以在大括弧中加入要評估的表達式。寫完信息後按Enter。
5.5 監視(Watch)
當程式只有幾個變數時,變數面板可能足以跟蹤變數狀態。但是,如果程式中有幾十個甚至上百個變數,該怎麼辦呢?如何關註單個變數受所有正在執行的程式的影響就變得很麻煩。
如果你想在不使用變數面板的情況下關註一個(或多個)變數,可以將該變數添加到觀察面板。當調試器運行時,觀察面板會跟蹤所選變數的狀態。該面板將表達式作為輸入,併在每一行代碼執行時更新變數。要在觀察面板中添加變數,請單擊 "添加表達式 "並輸入變數名。或者,也可以在編輯器中突出顯示變數,右鍵單擊,然後單擊添加到觀察。
試試看 在編輯器中打開watch.py,在greeting = ' Hello World'處設置斷點,然後啟動調試器。調試器在斷點處暫停後,將變數total添加到 Watch 面板。
查看代碼的每一行,註意變數賦值在代碼執行過程中的變化。
註意 當調試器啟動時,total 的值反映 NameError: name 'total' is not defined(名稱'total'未定義)。出現這種情況的原因是程式尚未執行定義變數的代碼行。一旦程式執行 total = 0,變數值就會更新為 0。 如果同一變數名在調用棧的不同位置使用(例如不同作用域),則以最新的變數名為準。當幀退出並從堆棧中移除時,Watch 面板會顯示下一個最高作用域中的變數值。
watch.py 中有六個變數:greeting、total、iteration、numbers、num 和 iteration_num。當調試器走過程式的每一行時,列表就會增加,以包括執行的每個變數。當調試器走過每一行代碼時,你可以通過查看觀察面板更好地關註總計的狀態。
5.6 調試控制台(The Debug Console)
調試程式時,您可以在調試控制臺中嘗試潛在的錯誤修複方法,而不是修改代碼後重新啟動。通過調試控制台,您可以在程式當前狀態下嘗試代碼,而無需停止調試器。您可以在調試控制臺中嘗試不同的方案,併在調試器暫停時將修正結果複製到程式中。
調試控制台在編輯器中提供了Python讀取-評估-列印-迴圈 (REPL Read-Eval-Print-Loop) 功能。通過調試控制台,您可以訪問和修改程式的所有變數,調用函數,求值表達式,以及使用程式的當前狀態運行任何您喜歡的代碼。控制臺中的任何操作都會影響程式的當前狀態。此外,調試控制台輸入支持語法著色、縮進、自動關閉引號以及活動編輯器模式的其他語言特性。
您可以通過以下三種方式訪問調試控制台:
- 運行視圖: 單擊調試控制台圖標。
-
鍵盤快捷鍵: 按 Cmd/Ctrl+Shift+Y。
-
主菜單: 查看 -> 調試控制台。
調試控制台會在您輸入時顯示建議。按Enter鍵後,表達式將被評估。要輸入多行,請在兩行之間按下Shift+Enter 鍵。
在調試控制臺中,可以直接調用函數並評估結果。如果調用的函數有斷點,則可以逐步查看函數代碼。退出函數後,你仍然處於與之前相同的程式狀態。你還可以使用調試控制台更改變數,運行程式中沒有的代碼。
試用:在編輯器中打開Fibonacci_generator.py文件。Fibonacci_generator.py文件包含生成斐波那契數字列表的程式。斐波那契數構成一個序列,序列中的下一個數字是序列中前兩個數字之和(例如 1、1、2、3、5、8、13、21)。程式啟動時,會提示用戶輸入程式應生成的數字總數。為了演示調試控制台,故意在程式中添加了一個錯誤。請按照以下說明使用調試控制台修複錯誤:
- 在終端運行程式,根據提示輸入1作為要生成的斐波納契數。程式成功運行並返回 [1]。
- 再次在終端運行程式,根據提示輸入2作為要生成的斐波那契數。程式成功運行並返回 [1,2]。
- 再次在終端運行程式,根據提示輸入要生成的斐波那契數 3。這次程式運行時停滯了。在鍵盤上按 Ctrl+C 退出程式。退出程式後,終端會出現一個錯誤:
How many Fibonacci numbers would you like to generate? 3
^CTraceback (most recent call last):
File "/home/andrew/code/Code_Samples/Code Samples/debugger/Fibonacci_generator.py", line 18, in <module>
print(gen_fib())
File "/home/andrew/code/Code_Samples/Code Samples/debugger/Fibonacci_generator.py", line 12, in gen_fib
while i < (count - 1):
KeyboardInterrupt
在計數 > 2 時的 elif 語句中,i == 1 似乎有問題。可以認為程式中的錯誤就出在這裡。
- 在i == 1處設置斷點並啟動調試器。出現提示時,輸入3。
調試器在斷點處暫停後,查看變數面板,確認變數是否反映了適當的值。
- Step over到 while 迴圈的最後一行
註意到儘管已經生成了所需的斐波納契數,迴圈仍開始了另一次迭代。繼續跳過 while 迴圈,程式會生成相同的斐波納契數,而且 while 迴圈從未中斷過。該程式是一個無限迴圈。
- 啟動調試器並打開調試控制台
調試器在斷點處停止後,輸入i+=1 以遞增 i 的值。
在變數面板中,i 的值從 1 變為 2。 現在,繼續調試程式時,執行代碼的其餘部分,只生成三個斐波那契數字。
5.7 啟動配置
啟動配置可讓你配置不同調試會話的運行方式,並將這些配置持久保存在 launch.json 文件中。launch.json 文件保存在項目根目錄下的 .vscode 文件夾中,也可在用戶或工作區設置中訪問。要進行調試,launch.json 文件中至少需要一個配置。
要創建 launch.json 文件,請在運行視圖中單擊創建 launch.json 文件。或者,你也可以從 "運行 "菜單中選擇 "運行" ➪ "打開配置 "來創建 launch.json 文件。
Visual Studio Code會從命令面板打開配置菜單,提示您選擇預設配置作為新配置的啟動模板。
Python 擴展提供了以下預設配置:
- Python 文件-調試當前活動的 Python 文件。
- 模塊-通過使用 -m 調用 Python 模塊來調試該模塊。
- 遠程連接-為調試伺服器監聽提供主機名和埠號。
- 使用進程 ID 附加-當運行在 Visual Studio Code 之外啟動的 Python 腳本時,將調試器附加到非調試模式下的 Python 進程。附加到進程需要進程 ID。
該擴展還為網路應用程式提供了三種預設配置:
- Django
- Flask
- Pyramid
要瞭解有關調試Django應用程式的更多信息,請參閱代碼.visualstudio.com/docs/python/tutorial-django#_explore-the-debugger 的Django教程。要瞭解有關調試 Flask 應用程式的更多信息,請參閱位於 code.visualstudio.com/docs/python/tutorial-flask#_run-the-app-in-the-debugger 的 Flask 教程。
選擇啟動模板後,launch.json文件將添加到 .vscode 文件夾中,併在編輯器中打開。
編輯 launch.json 文件時,IntelliSense 會提示(Ctrl+空格鍵)可用屬性列表。您也可以對文件中的所有屬性使用懸停幫助。由於不同語言的屬性可能不同,使用懸停幫助可以瞭解有關屬性的更多信息。
launch.json 文件可以包含任意數量的配置。要添加配置,請從運行菜單或 launch.json 編輯器中單擊添加配置。
這裡提供了 launch.json 文件可用的核心設置:
- name -為出現在 Visual Studio 代碼下拉列表中的調試配置提供名稱。
- type-指定要使用的調試器類型;對於 Python 代碼,將其設置為 python。
- request-指定開始調試的模式:
- launch: 在程式中指定的文件上啟動調試器。
- attach(附加): 將調試器附加到遠程伺服器上已經運行的進程上,該進程不能隨意重啟。本地需要與程式中指定的相同的源代碼文件。
- program-提供 Python 程式入口模塊(啟動文件)的完整路徑。預設配置中經常使用的 ${file} 值,會使用編輯器中的當前活動文件。通過指定啟動文件,可以確保無論打開哪個文件,都能以相同的入口點啟動程式。
- python- 指向用於調試的 Python 解釋器的完整路徑。如果未指定,則預設使用 python.pythonPath 設置中指定的解釋器,相當於使用 ${config:python.pythonPath} 值。要使用其他解釋器,請在調試配置的 python 屬性中指定其路徑。
- args-指定傳遞給程式的參數。參數字元串中以空格分隔的每個元素都應包含在引號中。
- cwd-指定調試器的當前工作目錄,它是代碼中使用的任何相對路徑的基本文件夾。如果省略,當前工作目錄預設為${workspaceFolder},即編輯器中打開的文件夾。或者,也可以使用在每個平臺上定義的自定義環境變數,其中包含要使用的 Python 解釋器的完整路徑,這樣就不需要額外的文件夾路徑了。
其他配置請訪問 code.visualstudio.com/docs/python/debugging#_set-configuration-options。還有一些非Python 特有的附加屬性,可以在 launch.json 中設置。要瞭解更多信息,請參閱 code.visualstudio.com/docs/editor/debugging#_launchjson-attributes。