sys.monitoring
— 執行事件監控¶
3.12 新版功能.
備註
sys.monitoring
是 sys
模組中的一個名稱空間,而不是一個獨立的模組,因此無需 import sys.monitoring
,只需 import sys
,然後使用 sys.monitoring
。
此名稱空間提供訪問啟用和控制事件監控所需的函式和常量。
程式執行時會發生事件,這些事件可能對監控執行的工具感興趣。sys.monitoring
名稱空間提供了在感興趣的事件發生時接收回調的方法。
監控 API 由三個元件組成
工具識別符號¶
工具識別符號是一個整數及其關聯的名稱。工具識別符號用於阻止工具相互干擾,並允許多個工具同時執行。目前,工具是完全獨立的,不能用於相互監控。此限制將來可能會解除。
在註冊或啟用事件之前,工具應選擇一個識別符號。識別符號是 0 到 5(包括 0 和 5)範圍內的整數。
註冊和使用工具¶
- sys.monitoring.use_tool_id(tool_id: int, name: str, /) None ¶
必須在可以使用 tool_id 之前呼叫。tool_id 必須在 0 到 5(包括 0 和 5)的範圍內。如果 tool_id 正在使用中,則會引發
ValueError
。
- sys.monitoring.free_tool_id(tool_id: int, /) None ¶
當工具不再需要 tool_id 時應呼叫此函式。在釋放 tool_id 之前,將呼叫
clear_tool_id()
。
- sys.monitoring.get_tool(tool_id: int, /) str | None ¶
如果 tool_id 正在使用中,則返回工具的名稱,否則返回
None
。tool_id 必須在 0 到 5(包括 0 和 5)的範圍內。
所有 ID 在 VM 中都被視為相同,但為了方便工具協作,預定義了以下 ID
sys.monitoring.DEBUGGER_ID = 0
sys.monitoring.COVERAGE_ID = 1
sys.monitoring.PROFILER_ID = 2
sys.monitoring.OPTIMIZER_ID = 5
事件¶
支援以下事件
- sys.monitoring.events.BRANCH_LEFT¶
一個條件分支向左。
由工具決定如何呈現“左”和“右”分支。不保證哪個分支是“左”哪個是“右”,但它在程式執行期間將保持一致。
- sys.monitoring.events.BRANCH_RIGHT¶
一個條件分支向右。
- sys.monitoring.events.CALL¶
Python 程式碼中的呼叫(事件在呼叫之前發生)。
- sys.monitoring.events.C_RAISE¶
從任何可呼叫物件引發的異常,除了 Python 函式(事件在退出後發生)。
- sys.monitoring.events.C_RETURN¶
從任何可呼叫物件返回,除了 Python 函式(事件在返回後發生)。
- sys.monitoring.events.EXCEPTION_HANDLED¶
一個異常被處理。
- sys.monitoring.events.INSTRUCTION¶
一個 VM 指令即將執行。
- sys.monitoring.events.JUMP¶
在控制流圖中發生無條件跳轉。
- sys.monitoring.events.LINE¶
一個指令即將執行,其行號與前一個指令不同。
- sys.monitoring.events.PY_RESUME¶
Python 函式的恢復(適用於生成器和協程函式),除了
throw()
呼叫。
- sys.monitoring.events.PY_RETURN¶
從 Python 函式返回(在返回之前立即發生,被呼叫者的幀將在堆疊上)。
- sys.monitoring.events.PY_START¶
Python 函式的開始(在呼叫之後立即發生,被呼叫者的幀將在堆疊上)
- sys.monitoring.events.PY_THROW¶
一個 Python 函式透過
throw()
呼叫恢復。
- sys.monitoring.events.PY_UNWIND¶
在異常展開期間退出 Python 函式。這包括直接在函式內部引發並允許繼續傳播的異常。
- sys.monitoring.events.PY_YIELD¶
從 Python 函式產出(在產出之前立即發生,被呼叫者的幀將在堆疊上)。
- sys.monitoring.events.RAISE¶
一個異常被引發,除了那些導致
STOP_ITERATION
事件的異常。
- sys.monitoring.events.STOP_ITERATION¶
引發了一個人為的
StopIteration
;參見 STOP_ITERATION 事件。
將來可能會新增更多事件。
這些事件是 sys.monitoring.events
名稱空間的屬性。每個事件都表示為一個 2 的冪整數常量。要定義一組事件,只需將各個事件按位或運算。例如,要指定 PY_RETURN
和 PY_START
事件,請使用表示式 PY_RETURN | PY_START
。
- sys.monitoring.events.NO_EVENTS¶
是
0
的別名,因此使用者可以進行顯式比較,例如if get_events(DEBUGGER_ID) == NO_EVENTS: ...
設定此事件將停用所有事件。
區域性事件¶
區域性事件與程式的正常執行相關聯,併發生在明確定義的位置。所有區域性事件都可以停用。區域性事件包括
已棄用的事件¶
BRANCH
BRANCH
事件在 3.14 中已棄用。使用 BRANCH_LEFT
和 BRANCH_RIGHT
事件將提供更好的效能,因為它們可以獨立停用。
輔助事件¶
輔助事件可以像其他事件一樣被監控,但由另一個事件控制
C_RETURN
和 C_RAISE
事件由 CALL
事件控制。C_RETURN
和 C_RAISE
事件只有在監控相應的 CALL
事件時才可見。
其他事件¶
其他事件不一定與程式中的特定位置繫結,並且無法單獨停用。
可以監控的其他事件包括
STOP_ITERATION 事件¶
PEP 380 指定從生成器或協程返回一個值時會引發 StopIteration
異常。然而,這是一種非常低效的返回值方式,因此一些 Python 實現,特別是 CPython 3.12+,除非異常對其他程式碼可見,否則不會引發異常。
為了允許工具監控真實的異常而不會減慢生成器和協程的速度,提供了 STOP_ITERATION
事件。STOP_ITERATION
可以區域性停用,不像 RAISE
。
請注意,STOP_ITERATION
事件和 StopIteration
異常的 RAISE
事件是等效的,並且在生成事件時被視為可互換。出於效能原因,實現將優先選擇 STOP_ITERATION
,但可能會生成帶有 StopIteration
的 RAISE
事件。
開啟和關閉事件¶
為了監控事件,必須開啟它並註冊相應的回撥。可以透過全域性和/或針對特定程式碼物件設定事件來開啟或關閉事件。即使事件全域性和區域性都開啟,它也只會觸發一次。
全域性設定事件¶
可以透過修改受監控的事件集來全域性控制事件。
- sys.monitoring.set_events(tool_id: int, event_set: int, /) None ¶
啟用在 event_set 中設定的所有事件。如果 tool_id 未在使用中,則引發
ValueError
。
預設情況下沒有事件是活動的。
每個程式碼物件事件¶
事件也可以按每個程式碼物件進行控制。下面定義的接受 types.CodeType
的函式應該準備好接受來自非 Python 定義函式(參見 監控 C API)的類似物件。
停用事件¶
- sys.monitoring.DISABLE¶
一個特殊值,可以從回撥函式返回以停用當前程式碼位置的事件。
可以透過從回撥函式返回 sys.monitoring.DISABLE
來停用特定程式碼位置的區域性事件。這不會更改已設定的事件或相同事件的任何其他程式碼位置。
停用特定位置的事件對於高效能監控非常重要。例如,如果偵錯程式停用除少數斷點之外的所有監控,則程式可以在沒有開銷的情況下在偵錯程式下執行。
- sys.monitoring.restart_events() None ¶
重新啟用所有由
sys.monitoring.DISABLE
為所有工具停用的事件。
註冊回撥函式¶
- sys.monitoring.register_callback(tool_id: int, event: int, func: Callable | None, /) Callable | None ¶
為給定的 tool_id 註冊 event 的可呼叫物件 func
如果已為給定的 tool_id 和 event 註冊了另一個回撥,則取消註冊並返回它。否則,
register_callback()
返回None
。引發一個 審計事件
sys.monitoring.register_callback
,其引數為func
。
可以透過呼叫 sys.monitoring.register_callback(tool_id, event, None)
來取消註冊函式。
回撥函式可以隨時註冊和取消註冊。
無論事件是全域性還是區域性開啟,回撥都只調用一次。因此,如果您的程式碼可以同時為全域性和區域性事件開啟一個事件,那麼回撥需要編寫以處理任一觸發器。
回撥函式引數¶
- sys.monitoring.MISSING¶
一個特殊值,傳遞給回撥函式以指示呼叫沒有引數。
當活動事件發生時,會呼叫已註冊的回撥函式。返回除 DISABLE
之外的物件的函式將不起作用。不同的事件將向回撥函式提供不同的引數,如下所示
-
func(code: CodeType, instruction_offset: int) -> object
-
func(code: CodeType, instruction_offset: int, retval: object) -> object
CALL
、C_RAISE
和C_RETURN
(arg0 可以專門是MISSING
)func(code: CodeType, instruction_offset: int, callable: object, arg0: object) -> object
code 表示正在進行呼叫的程式碼物件,而 callable 是即將被呼叫(並因此觸發事件)的物件。如果沒有引數,arg0 將設定為
sys.monitoring.MISSING
。對於例項方法,callable 將是類上找到的函式物件,arg0 設定為例項(即方法的
self
引數)。RAISE
、RERAISE
、EXCEPTION_HANDLED
、PY_UNWIND
、PY_THROW
和STOP_ITERATION
func(code: CodeType, instruction_offset: int, exception: BaseException) -> object
LINE
:func(code: CodeType, line_number: int) -> object
BRANCH_LEFT
、BRANCH_RIGHT
和JUMP
func(code: CodeType, instruction_offset: int, destination_offset: int) -> object
請注意,destination_offset 是程式碼接下來將執行的位置。
-
func(code: CodeType, instruction_offset: int) -> object