Python程式員Visual Studio Code指南5調試

来源:https://www.cnblogs.com/testing-/p/17640620.html
-Advertisement-
Play Games

隨著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)命令可以方便地停止調試器,保存當前文件,然後用最近的修改重新啟動調試器。

參考資料

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。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 我們已經介紹了radash的相關信息和部分Array相關方法,詳情可前往主頁查看; 本篇我們繼續介紹radash中Array的相關方法; 下期我們將介紹解析radash中剩餘的 Array相關方法,並整理出Array方法使用目錄,包括文章說明和腦圖說明。 Radash的Array相關方法詳解 ...
  • 大家好,我是 Java陳序員。 今天,給大家介紹一個基於 Vue 全家桶實現的“網易雲”播放器。 關註微信公眾號:【Java陳序員】,獲取開源項目分享、AI副業分享、超200本經典電腦電子書籍等。 項目介紹 YesPlayMusic —— 一款高顏值的第三方網易雲播放器,支持 Windows / ...
  • 本文分享自華為雲社區《3月閱讀周·你不知道的JavaScript | ES6生成器,看似同步的非同步流程式控制製表達風格》,作者: 葉一一。 生成器 打破完整運行 JavaScript開發者在代碼中幾乎普遍依賴的一個假定:一個函數一旦開始執行,就會運行到結束,期間不會有其他代碼能夠打斷它並插入其間。 ES ...
  • 目錄一、爬取目標1.1 效果截圖1.2 演示視頻1.3 軟體說明二、代碼講解2.1 爬蟲採集模塊2.2 軟體界面模塊2.3 日誌模塊三、獲取源碼及軟體 一、爬取目標 用python開發的xhs爬蟲採集軟體,可自動抓取小紅書評論數據,並且含二級評論數據。 為什麼有了源碼還開發界面軟體呢?方便不懂編程代 ...
  • 1、 Pythonic - 很Python 寫一段代碼生成1到100之間的數字的平方的列表,答案是: 1, 4, 9, 16... 如果你這樣寫,你就不Pythonic了: 解釋 nums = [] for i in range(1, 101): nums.append(i*i) print(num ...
  • 拓展閱讀 MySQL View MySQL truncate table 與 delete 清空表的區別和坑 MySQL Ruler mysql 日常開發規範 MySQL datetime timestamp 以及如何自動更新,如何實現範圍查詢 MySQL 06 mysql 如何實現類似 oracl ...
  • C++ 解引用 獲取記憶體地址和值 在上一頁的示例中,我們使用了指針變數來獲取變數的記憶體地址(與引用運算符 & 一起使用)。但是,你也可以使用指針來獲取變數的值,這可以通過使用 * 運算符(解引用運算符)來實現: string food = "Pizza"; // 變數聲明 string* ptr = ...
  • 大家好,我是白夜,今天給大家聊聊面向對象的三大特征——封裝 一、包(package) 1.1、包的引入 先來看看我們之前寫的代碼結構 以上代碼存在的問題 所有類寫在一個目錄下麵,非常難管理,因為以後項目不可能只有這麼幾個類,當類數量很大的時候,就不容易管理了。 不能寫同名但是不同需求的類。 為瞭解決 ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...