sys.monitoring
— 执行事件监视¶
在 3.12 版本中添加。
注意
sys.monitoring
是 sys
模块中的一个命名空间,而不是一个独立模块,因此无需 import sys.monitoring
,只需 import sys
然后使用 sys.monitoring
即可。
此命名空间提供对激活和控制事件监视所需的函数和常量的访问。
程序执行时,可能会发生一些事件,这些事件可能对监视执行的工具感兴趣。 sys.monitoring
命名空间提供了在感兴趣的事件发生时接收回调的方法。
监视 API 包含三个组件
工具标识符¶
工具标识符是一个整数和一个关联的名称。工具标识符用于阻止工具互相干扰,并允许多个工具同时运行。目前,工具完全独立,不能用于监视彼此。此限制可能会在未来解除。
在注册或激活事件之前,工具应选择一个标识符。标识符是 0 到 5(包括 5)范围内的整数。
注册和使用工具¶
- sys.monitoring.use_tool_id(tool_id: int, name: str, /) None ¶
必须在使用tool_id之前调用。tool_id必须在 0 到 5(包括 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(包括 5)的范围内。
VM 对所有 ID 的处理方式在事件方面相同,但预定义了以下 ID 以便于工具协作
sys.monitoring.DEBUGGER_ID = 0
sys.monitoring.COVERAGE_ID = 1
sys.monitoring.PROFILER_ID = 2
sys.monitoring.OPTIMIZER_ID = 5
没有设置 ID 的义务,也没有任何内容阻止工具使用 ID,即使该 ID 已在使用中。但是,鼓励工具使用唯一的 ID 并尊重其他工具。
事件¶
支持以下事件
- 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¶
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: ...
事件分为三组
局部事件¶
局部事件与程序的正常执行相关,并且发生在明确定义的位置。所有局部事件都可以禁用。局部事件为
辅助事件¶
辅助事件可以像其他事件一样进行监控,但受另一个事件控制
事件 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
。
默认情况下没有活动事件。
每个代码对象事件¶
事件还可以基于每个代码对象进行控制。
- 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
来禁用特定代码位置的本地事件。这不会更改设置的事件或同一事件的任何其他代码位置。
禁用特定位置的事件对于高性能监控非常重要。例如,如果调试器禁用了除几个断点之外的所有监控,则可以在没有开销的情况下在调试器下运行程序。
- 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