sys.monitoring — 執行事件監控

在 3.12 版本中新增。


註解

sys.monitoringsys 模組中的一個名稱空間,而不是一個獨立的模組,因此無需 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 時應呼叫此方法。

註解

free_tool_id() 不會停用與 tool_id 關聯的全域性或本地事件,也不會取消註冊任何回撥函式。此函式僅用於通知 VM,特定的 tool_id 不再使用。

sys.monitoring.get_tool(tool_id: int, /) str | None

如果 tool_id 正在使用,則返回工具的名稱,否則返回 Nonetool_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

發生條件分支(被執行或不被執行)。

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

透過 throw() 呼叫恢復 Python 函式。

sys.monitoring.events.PY_UNWIND

在異常展開期間從 Python 函式退出。

sys.monitoring.events.PY_YIELD

從 Python 函式產生值(發生在 yield 之前,被呼叫者的幀將在堆疊上)。

sys.monitoring.events.RAISE

引發異常,除了那些導致 STOP_ITERATION 事件的異常。

sys.monitoring.events.RERAISE

重新引發異常,例如在 finally 程式碼塊的末尾。

sys.monitoring.events.STOP_ITERATION

引發一個人為的 StopIteration 異常;請參閱 STOP_ITERATION 事件

未來可能會新增更多事件。

這些事件是 sys.monitoring.events 名稱空間的屬性。每個事件都表示為一個 2 的冪的整數常量。要定義一組事件,只需將各個事件按位或運算即可。例如,要指定 PY_RETURNPY_START 事件,請使用表示式 PY_RETURN | PY_START

sys.monitoring.events.NO_EVENTS

0 的別名,以便使用者可以進行顯式比較,例如

if get_events(DEBUGGER_ID) == NO_EVENTS:
    ...

事件分為三組

本地事件

本地事件與程式的正常執行相關聯,並且發生在明確定義的位置。所有本地事件都可以停用。本地事件有

輔助事件

輔助事件可以像其他事件一樣進行監視,但由另一個事件控制

C_RETURNC_RAISE 事件由 CALL 事件控制。 只有在監視相應的 CALL 事件時,才會看到 C_RETURNC_RAISE 事件。

其他事件

其他事件不一定與程式中的特定位置相關聯,並且不能單獨停用。

可以監視的其他事件有

STOP_ITERATION 事件

PEP 380 指定,當從生成器或協程返回值時,會引發 StopIteration 異常。但是,這是一種非常低效的返回值方式,因此一些 Python 實現(特別是 CPython 3.12+)不會引發異常,除非它對其他程式碼可見。

為了允許工具在不減慢生成器和協程速度的情況下監視真實異常,提供了 STOP_ITERATION 事件。與 RAISE 不同,STOP_ITERATION 可以在本地停用。

啟用和關閉事件

為了監視事件,必須啟用它並註冊相應的回撥。可以透過全域性設定或為特定程式碼物件設定事件來啟用或關閉事件。

全域性設定事件

可以透過修改正在監視的事件集來全域性控制事件。

sys.monitoring.get_events(tool_id: int, /) int

返回表示所有活動事件的 int

sys.monitoring.set_events(tool_id: int, event_set: int, /) None

啟用 event_set 中設定的所有事件。如果 tool_id 未使用,則引發 ValueError

預設情況下,沒有事件處於活動狀態。

每個程式碼物件事件

也可以在每個程式碼物件的基礎上控制事件。下面定義的接受 types.CodeType 的函式應該準備好接受來自未在 Python 中定義的函式的類似物件(請參閱 Monitoring C API)。

sys.monitoring.get_local_events(tool_id: int, code: CodeType, /) int

返回 code 的所有本地事件

sys.monitoring.set_local_events(tool_id: int, code: CodeType, event_set: int, /) None

啟用 codeevent_set 中設定的所有本地事件。如果 tool_id 未使用,則引發 ValueError

本地事件會新增到全域性事件中,但不會遮蔽全域性事件。換句話說,無論本地事件如何,所有全域性事件都將為程式碼物件觸發。

停用事件

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_idevent 註冊了另一個回撥,則會取消註冊並返回該回調。否則,register_callback() 返回 None

可以透過呼叫 sys.monitoring.register_callback(tool_id, event, None) 來取消註冊函式。

回撥函式可以隨時註冊和取消註冊。

註冊或取消註冊回撥函式將生成 sys.audit() 事件。

回撥函式引數

sys.monitoring.MISSING

一個特殊的值,傳遞給回撥函式,表示該呼叫沒有引數。

當活動事件發生時,將呼叫已註冊的回撥函式。不同的事件將為回撥函式提供不同的引數,如下所示

  • PY_STARTPY_RESUME

    func(code: CodeType, instruction_offset: int) -> DISABLE | Any
    
  • PY_RETURNPY_YIELD

    func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any
    
  • CALL, C_RAISEC_RETURN

    func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any
    

    如果沒有引數,則 arg0 設定為 sys.monitoring.MISSING

  • RAISE, RERAISE, EXCEPTION_HANDLED, PY_UNWIND, PY_THROWSTOP_ITERATION

    func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any
    
  • LINE:

    func(code: CodeType, line_number: int) -> DISABLE | Any
    
  • BRANCHJUMP

    func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any
    

    請注意,destination_offset 是程式碼接下來將執行的位置。對於未採用的分支,這將是分支後指令的偏移量。

  • INSTRUCTION:

    func(code: CodeType, instruction_offset: int) -> DISABLE | Any