# 重要对象及关键源码
# 运行时重要对象
在CPython虚拟机运行期间,比较重要的一些对象包括:
-
Code Object:表示Python源代码的编译结果,包括字节码指令、常量池、变量名等信息,是Python程序的执行单位。 -
Frame Object:表示函数调用时的栈帧,保存了函数的局部变量、参数、返回地址、当前行号等信息,是Python虚拟机执行代码时的基本单位。 -
Function Object:表示函数对象,保存了函数的代码、全局变量等信息,是一种可调用的对象。 -
Module Object:表示模块对象,保存了模块的全局变量、函数等信息。 -
Type Object:表示类型对象,是 Python 对象模型的基石之一,每个对象都有一个对应的类型对象,决定了对象所能够支持的操作和行为。类型对象本身也是 Python 对象,其类型是type。 -
Class Object:表示类对象,在 Python 中,每个类都有一个对应的类对象,类对象包含了类定义中的所有方法和属性。类对象也是一个 Python 对象,其类型是type。
这些对象之间的关系如下:
-
Code Object对象是函数对象和模块对象的核心组成部分,描述了函数或模块的执行流程、变量名等信息。 -
Function Object对象是一个可调用对象,与Code Object对象关联,保存了函数的代码、全局变量等信息,同时可以通过函数名称访问。 -
Module Object对象是一个全局作用域,保存了模块的全局变量、函数等信息,同时也是一个命名空间,可以通过模块名称访问。 -
Frame Object对象保存了函数调用时的信息,包括函数的局部变量、参数、返回地址、当前行号等信息,同时也维护了函数调用栈的状态,是Python虚拟机执行代码时的基本单位,每个栈帧与一个Code Object对象相关联,同时也可以访问上层栈帧的变量信息。 - 类型对象是所有 Python 对象的基类,所有对象都有一个对应的类型对象,类型对象之间也可以存在继承关系;
- 类对象是创建实例对象的工厂,实例对象包含了对应的类对象、属性和方法等;
# PyCodeObject
/* Bytecode object */
typedef struct {
PyObject_HEAD
int co_argcount; /* 参数个数 #arguments, except *args */
int co_kwonlyargcount; /* 关键字参数个数 #keyword only arguments */
int co_nlocals; /* 局部变量个数 #local variables */
int co_stacksize; /* 执行代码所需栈空间 #entries needed for evaluation stack */
int co_flags; /* 标识 CO_..., see below */
int co_firstlineno; /* 代码块首行行号 first source line number */
PyObject *co_code; /* 指令操作码,也就是字节码 instruction opcodes */
PyObject *co_consts; /* 常量列表 list (constants used) */
PyObject *co_names; /* 名字列表 list of strings (names used) */
PyObject *co_varnames; /* 局部变量名列表 tuple of strings (local variable names) */
PyObject *co_freevars; /* tuple of strings (free variable names) */
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
/* The rest aren't used in either hash or comparisons, except for co_name,
used in both. This is done to preserve the name and line number
for tracebacks and debuggers; otherwise, constant de-duplication
would collapse identical functions/lambdas defined on different lines.
*/
Py_ssize_t *co_cell2arg; /* Maps cell vars which are arguments. */
PyObject *co_filename; /* unicode (where it was loaded from) */
PyObject *co_name; /* unicode (name, for reference) */
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
Objects/lnotab_notes.txt for details. */
void *co_zombieframe; /* for optimization only (see frameobject.c) */
PyObject *co_weakreflist; /* to support weakrefs to code objects */
/* Scratch space for extra data relating to the code object.
Type is a void* to keep the format private in codeobject.c to force
people to go through the proper APIs. */
void *co_extra;
} PyCodeObject;
# PyEval_EvalFrameEx
PyEval_EvalFrameEx 函数最终调用 _PyEval_EvalFrameDefault 函数执行 frame 对象上的代码对象。虽然它体量巨大,超过 3 千行代码,逻辑却非常直白 —— 内部由无限 for 循环逐条遍历并处理字节码,每执行完一条字节码就自增 f_lasti 字段。