sys.monitoring
--- 執行事件監控¶
在 3.12 版被加入.
備註
sys.monitoring
是 sys
模組內的一個命名空間,不是一個獨立的模組,所以不需要 import sys.monitoring
,只需 import sys
然後使用 sys.monitoring
。
此命名空間提供對啟動和控制事件監控所需的函式和常數的存取。
當程式執行時,會發生一些能被監控工具關注的事件。sys.monitoring
命名空間提供了在發生欲關注事件時接收回呼的方法。
監控 API 由三個元件組成:
工具識別器¶
工具識別器是一個整數和關聯的名稱。工具識別器用於防止工具相互干擾並允許多個工具同時運作。目前工具是完全獨立的,不能用來互相監控。將來此限制可能會取消。
在註冊或啟動事件之前,工具應選擇一個識別器。識別器是 0 到 5(含)範圍內的整數。
註冊和使用工具¶
- sys.monitoring.use_tool_id(tool_id: int, name: str, /) None ¶
必須在使用 tool_id 之前呼叫。tool_id 必須在 0 到 5(含)範圍內。如果 tool_id 正在使用,則引發
ValueError
。
備註
free_tool_id()
不會停用與 tool_id 相關的全域或區域事件,也不會取消註冊任何回呼函式。這個函式只是用來通知虛擬機器 (VM) 不再使用特定的 tool_id。
- sys.monitoring.get_tool(tool_id: int, /) str | None ¶
如果 tool_id 正在使用,則回傳該工具的名稱,否則回傳
None
。tool_id 必須在 0 到 5(含)範圍內。
對於事件,虛擬機器對所有 ID 的處理都是相同的,但預先定義了以下 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¶
虛擬機器指令即將被執行。
- sys.monitoring.events.JUMP¶
在控制流程圖中進行無條件跳轉。
- sys.monitoring.events.LINE¶
即將執行的指令與前一條指令的列號不同。
- sys.monitoring.events.PY_RESUME¶
Python 函式的繼續執行(對於產生器和協程函式),除了
throw()
呼叫。
- sys.monitoring.events.PY_RETURN¶
從 Python 函式回傳(發生在即將回傳之前,被呼叫者的 frame 將位於堆疊上)。
- sys.monitoring.events.PY_START¶
Python 函式的開始(在呼叫後立即發生,被呼叫者的 frame 將位於堆疊上)
- sys.monitoring.events.PY_THROW¶
Python 函式透過
throw()
呼叫來繼續。
- sys.monitoring.events.PY_UNWIND¶
在例外展開 (unwind) 期間從 Python 函式退出。
- sys.monitoring.events.PY_YIELD¶
來自 Python 函式的 yield(在即將 yield 之前發生,被呼叫者的 frame 將位於堆疊上)。
- sys.monitoring.events.RAISE¶
例外被引發,除了那些會導致
STOP_ITERATION
的事件外。
- sys.monitoring.events.STOP_ITERATION¶
一個人為的
StopIteration
被引發;請參閱 STOP_ITERATION 事件。
將來可能會新增更多事件。
這些事件是 sys.monitoring.events
命名空間的屬性。每個事件以 2 次方的整數常數表示。要定義一組事件,只要將個別事件以 bitwise or 相接即可。例如,若要指定 PY_RETURN
和 PY_START
兩個事件,請使用運算式 PY_RETURN | PY_START
。
- sys.monitoring.events.NO_EVENTS¶
0
的別名,以便使用者可以進行明確比較,例如:if get_events(DEBUGGER_ID) == NO_EVENTS: ...
事件被分為三組:
區域事件¶
區域事件與程式的正常執行相關,並發生在明確定義的位置。所有區域事件都可以被停用。區域事件有:
附屬事件 (ancillary events)¶
附屬事件可以像其他事件一樣被監控,但由另一個事件所控制:
C_RETURN
和 C_RAISE
事件由 CALL
事件控制。只有當對應的 CALL
事件受到監控時,才會看到 C_RETURN
和 C_RAISE
事件。
其他事件¶
其他事件不一定與程式中的特定位置相關聯,也不能單獨停用。
其他可以監控的事件有:
STOP_ITERATION 事件¶
PEP 380 指出從產生器或協程回傳值時要引發 StopIteration
例外。然而,這是一種非常低效的回傳值方式,因此有一些 Python 實作(特別是 CPython 3.12+)不會引發例外,除非它對其他程式碼是可見的。
為了允許工具去監控真正的例外而不減慢產生器和協程的速度,提供了 STOP_ITERATION
事件。與 RAISE
不同,STOP_ITERATION
可以區域停用。
開啟和關閉事件¶
為了監控一個事件,必須打開它並註冊相應的回呼。可以透過將事件設定為全域或只為特定程式碼物件來開啟或關閉事件。
全域設定事件¶
可以透過修改正在監控的事件集合來全域地控制事件。
- sys.monitoring.set_events(tool_id: int, event_set: int, /) None ¶
啟動 event_set 中設定的所有事件。如果 tool_id 並未正在被使用,則引發
ValueError
。
預設沒有有效事件。
各別程式碼物件事件¶
事件還可以基於各別程式碼物件進行控制。下面定義的、接受 types.CodeType
的函式應該準備好接受來自 Python 中未定義函式的類似物件(請參閱 監控 C API)。
- sys.monitoring.set_local_events(tool_id: int, code: CodeType, event_set: int, /) None ¶
啟動 event_set 中針對 code 設定的所有區域事件。如果 tool_id 並未正在被使用,則引發
ValueError
。
區域事件會加入到全域事件中,但不會掩蓋它們。換句話說,無論區域事件如何,所有全域事件都將為程式碼物件觸發。
停用事件¶
- sys.monitoring.DISABLE¶
可以從回呼函式回傳的特殊值,以停用當前程式碼位置的事件。
可透過回呼函式回傳 sys.monitoring.DISABLE
來停用特定程式碼位置的區域事件。這不會改變被設定的事件,或相同事件的任何其他程式碼位置。
停用特定位置的事件對於高效能監控非常重要。舉例來說,如果除少數斷點外,偵錯器可以停用所有監控,那麼在偵錯器下執行程式就不會有任何開銷 (overhead)。
- 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(tool_id, event, None)
來取消註冊函式。
回呼函式可以隨時被註冊和取消註冊。
註冊或取消註冊回呼函式將產生 sys.audit()
事件。
回呼函式引數¶
- sys.monitoring.MISSING¶
傳遞給回呼函式的特殊值,表示該呼叫沒有引數。
當有效事件發生時,已註冊的回呼函式會被呼叫。不同的事件會為回呼函式提供不同的引數,如下所示:
-
func(code: CodeType, instruction_offset: int) -> DISABLE | Any
-
func(code: CodeType, instruction_offset: int, retval: object) -> DISABLE | Any
-
func(code: CodeType, instruction_offset: int, callable: object, arg0: object | MISSING) -> DISABLE | Any
如果沒有引數,arg0 將被設定為
sys.monitoring.MISSING
。 RAISE
、RERAISE
、EXCEPTION_HANDLED
、PY_UNWIND
、PY_THROW
和STOP_ITERATION
:func(code: CodeType, instruction_offset: int, exception: BaseException) -> DISABLE | Any
LINE
:func(code: CodeType, line_number: int) -> DISABLE | Any
-
func(code: CodeType, instruction_offset: int, destination_offset: int) -> DISABLE | Any
請注意,destination_offset 是程式碼接下來要執行的地方。對於未採用的分支,這將是該分支之後的指令的偏移量。
-
func(code: CodeType, instruction_offset: int) -> DISABLE | Any