代码对象

代码对象是 CPython 实现的底层细节。每个代码对象都表示尚未绑定到函数的一块可执行代码。

type PyCodeObject

用于描述代码对象的 C 结构体。此类型的字段随时可能更改。

PyTypeObject PyCode_Type

这是 PyTypeObject 的一个实例,表示 Python 代码对象

int PyCode_Check(PyObject *co)

如果 co 是一个 代码对象,则返回 true。此函数总是成功。

Py_ssize_t PyCode_GetNumFree(PyCodeObject *co)

返回代码对象中 自由(闭包)变量 的数量。

int PyUnstable_Code_GetFirstFree(PyCodeObject *co)
这是一个不稳定 API。它可能会在次要版本中未经警告而更改。

返回代码对象中第一个 自由(闭包)变量 的位置。

3.13 版本中已更改: 作为 不稳定的 C API 的一部分,从 PyCode_GetFirstFree 重命名。旧名称已弃用,但会一直可用,直到签名再次更改。

PyCodeObject *PyUnstable_Code_New(int argcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable)
这是一个不稳定 API。它可能会在次要版本中未经警告而更改。

返回一个新的代码对象。如果需要一个虚拟代码对象来创建帧,请改用 PyCode_NewEmpty()

由于字节码的定义经常变化,直接调用 PyUnstable_Code_New() 可能会使您绑定到特定的 Python 版本。

此函数的许多参数以复杂的方式相互依赖,这意味着对值的细微更改很可能导致不正确的执行或 VM 崩溃。请务必谨慎使用此函数。

3.11 版本中已更改: 添加了 qualnameexceptiontable 参数。

3.12 版本中已更改: 作为 不稳定的 C API 的一部分,从 PyCode_New 重命名。旧名称已弃用,但会一直可用,直到签名再次更改。

PyCodeObject *PyUnstable_Code_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable)
这是一个不稳定 API。它可能会在次要版本中未经警告而更改。

类似于 PyUnstable_Code_New(),但为仅限位置参数多了一个“posonlyargcount”参数。适用于 PyUnstable_Code_New 的注意事项也适用于此函数。

3.8 版本中新增: 作为 PyCode_NewWithPosOnlyArgs

3.11 版本中已更改: 添加了 qualnameexceptiontable 参数。

3.12 版本中已更改: 重命名为 PyUnstable_Code_NewWithPosOnlyArgs。旧名称已弃用,但会一直可用,直到签名再次更改。

PyCodeObject *PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
返回值:新引用。

返回一个新的空代码对象,带有指定的文件名、函数名和起始行号。如果执行,生成的代码对象将引发 Exception

int PyCode_Addr2Line(PyCodeObject *co, int byte_offset)

返回位于或之前 byte_offset 且在此之后结束的指令的行号。如果只需要帧的行号,请改用 PyFrame_GetLineNumber()

为了有效地迭代代码对象中的行号,请使用 PEP 626 中描述的 API

int PyCode_Addr2Location(PyObject *co, int byte_offset, int *start_line, int *start_column, int *end_line, int *end_column)

将传入的 int 指针设置为 byte_offset 处指令的源代码行号和列号。当任何特定元素的信息不可用时,将值设置为 0

如果函数成功则返回 1,否则返回 0。

在 3.11 版本中新增。

PyObject *PyCode_GetCode(PyCodeObject *co)

等效于 Python 代码 getattr(co, 'co_code')。返回一个对 PyBytesObject 的强引用,该对象表示代码对象中的字节码。如果发生错误,将返回 NULL 并引发异常。

PyBytesObject 可能是由解释器按需创建的,不一定代表 CPython 实际执行的字节码。此函数的主要用例是调试器和分析器。

在 3.11 版本中新增。

PyObject *PyCode_GetVarnames(PyCodeObject *co)

等效于 Python 代码 getattr(co, 'co_varnames')。返回一个对 PyTupleObject 的新引用,其中包含局部变量的名称。如果发生错误,将返回 NULL 并引发异常。

在 3.11 版本中新增。

PyObject *PyCode_GetCellvars(PyCodeObject *co)

等效于 Python 代码 getattr(co, 'co_cellvars')。返回一个对 PyTupleObject 的新引用,其中包含被嵌套函数引用的局部变量的名称。如果发生错误,将返回 NULL 并引发异常。

在 3.11 版本中新增。

PyObject *PyCode_GetFreevars(PyCodeObject *co)

等效于 Python 代码 getattr(co, 'co_freevars')。返回一个对 PyTupleObject 的新引用,其中包含 自由(闭包)变量 的名称。如果发生错误,将返回 NULL 并引发异常。

在 3.11 版本中新增。

int PyCode_AddWatcher(PyCode_WatchCallback callback)

callback 注册为当前解释器的代码对象观察者。返回一个 ID,该 ID 可以传递给 PyCode_ClearWatcher()。如果发生错误(例如,没有可用的观察者 ID),则返回 -1 并设置一个异常。

3.12 新版功能.

int PyCode_ClearWatcher(int watcher_id)

清除由 watcher_id 标识的观察者,该 watcher_id 之前由当前解释器的 PyCode_AddWatcher() 返回。成功时返回 0,错误时返回 -1 并设置一个异常(例如,如果给定的 watcher_id 从未注册过)。

3.12 新版功能.

type PyCodeEvent

代码对象观察者事件的枚举: - PY_CODE_EVENT_CREATE - PY_CODE_EVENT_DESTROY

3.12 新版功能.

typedef int (*PyCode_WatchCallback)(PyCodeEvent event, PyCodeObject *co)

代码对象观察者回调函数的类型。

如果 eventPY_CODE_EVENT_CREATE,则在 co 完全初始化后调用回调函数。否则,在 co 销毁发生之前调用回调函数,因此可以检查 co 的先前状态。

如果 eventPY_CODE_EVENT_DESTROY,在回调中获取对即将销毁的代码对象的引用将使其复活并阻止其在此刻被释放。当复活的对象稍后被销毁时,当时处于活动状态的任何观察者回调将再次被调用。

此 API 的用户不应依赖内部运行时实现细节。此类细节可能包括但不限于代码对象创建和销毁的确切顺序和时机。虽然这些细节的变化可能导致观察者可观察到的差异(包括是否调用回调),但它不会改变正在执行的 Python 代码的语义。

如果回调设置了异常,它必须返回 -1;此异常将使用 PyErr_WriteUnraisable() 打印为无法引发的异常。否则,它应该返回 0

进入回调时可能已经设置了挂起异常。在这种情况下,回调应返回 0,并保持相同的异常设置。这意味着回调不能调用任何其他可能设置异常的 API,除非它首先保存并清除异常状态,并在返回之前恢复它。

3.12 新版功能.

代码对象标志

代码对象包含一个标志位字段,可以将其作为 co_flags Python 属性检索(例如使用 PyObject_GetAttrString()),并使用 PyUnstable_Code_New() 和类似函数的 flags 参数进行设置。

名称以 CO_FUTURE_ 开头的标志对应于通常通过 future statements 可选择的功能。这些标志可以在 PyCompilerFlags.cf_flags 中使用。请注意,许多 CO_FUTURE_ 标志在当前 Python 版本中是强制性的,设置它们没有效果。

以下标志可用。有关其含义,请参阅其 Python 等效项的链接文档。

Flag

含义

CO_OPTIMIZED

inspect.CO_OPTIMIZED

CO_NEWLOCALS

inspect.CO_NEWLOCALS

CO_VARARGS

inspect.CO_VARARGS

CO_VARKEYWORDS

inspect.CO_VARKEYWORDS

CO_NESTED

inspect.CO_NESTED

CO_GENERATOR

inspect.CO_GENERATOR

CO_COROUTINE

inspect.CO_COROUTINE

CO_ITERABLE_COROUTINE

inspect.CO_ITERABLE_COROUTINE

CO_ASYNC_GENERATOR

inspect.CO_ASYNC_GENERATOR

CO_HAS_DOCSTRING

inspect.CO_HAS_DOCSTRING

CO_METHOD

inspect.CO_METHOD

CO_FUTURE_DIVISION

无影响 (__future__.division)

CO_FUTURE_ABSOLUTE_IMPORT

无影响 (__future__.absolute_import)

CO_FUTURE_WITH_STATEMENT

无影响 (__future__.with_statement)

CO_FUTURE_PRINT_FUNCTION

无影响 (__future__.print_function)

CO_FUTURE_UNICODE_LITERALS

无影响 (__future__.unicode_literals)

CO_FUTURE_GENERATOR_STOP

无影响 (__future__.generator_stop)

CO_FUTURE_ANNOTATIONS

__future__.annotations

额外信息

为了支持对帧评估的底层扩展,例如外部即时编译器,可以将任意额外数据附加到代码对象。

这些函数是不稳定 C API 层的一部分:此功能是 CPython 实现细节,API 可能会在没有弃用警告的情况下更改。

Py_ssize_t PyUnstable_Eval_RequestCodeExtraIndex(freefunc free)
这是一个不稳定 API。它可能会在次要版本中未经警告而更改。

返回一个新的不透明索引值,用于向代码对象添加数据。

您通常(每个解释器)调用此函数一次,并使用结果与 PyCode_GetExtraPyCode_SetExtra 一起操作单个代码对象上的数据。

如果 free 不为 NULL:当代码对象被解除分配时,将对存储在新索引下的非 NULL 数据调用 free。存储 PyObject 时使用 Py_DecRef()

3.6 版本中新增: 作为 _PyEval_RequestCodeExtraIndex

3.12 版本中已更改: 重命名为 PyUnstable_Eval_RequestCodeExtraIndex。旧的私有名称已弃用,但会一直可用,直到 API 更改。

int PyUnstable_Code_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
这是一个不稳定 API。它可能会在次要版本中未经警告而更改。

extra 设置为给定索引下存储的额外数据。成功时返回 0。失败时设置异常并返回 -1。

如果未在索引下设置数据,则将 extra 设置为 NULL 并返回 0,而不设置异常。

3.6 版本中新增: 作为 _PyCode_GetExtra

3.12 版本中已更改: 重命名为 PyUnstable_Code_GetExtra。旧的私有名称已弃用,但会一直可用,直到 API 更改。

int PyUnstable_Code_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
这是一个不稳定 API。它可能会在次要版本中未经警告而更改。

将给定索引下存储的额外数据设置为 extra。成功时返回 0。失败时设置异常并返回 -1。

3.6 版本中新增: 作为 _PyCode_SetExtra

3.12 版本中已更改: 重命名为 PyUnstable_Code_SetExtra。旧的私有名称已弃用,但会一直可用,直到 API 更改。