Python中PyCodeObject、PyFunctionObject、PyFrameObject的区别与联系
PyCodeObject:代码对象,就是一段代码编译后形成的对象,函数中对应的就是函数体的代码编译结果。
PyFunctionObject :函数对象,它是对PyCodeObject的封装,相当于 PyCodeObject + 函数def定义这一行代码。它在PyCodeObject基础上增加了函数的名称、所属的模块、参数默认值、globals、builtins。
PyFrameObject:函数执行时对应的栈帧,它用于承载PyFunctionObject在执行时所需要的动态信息。包括函数的实参、函数执行时所需的栈、全局变量、局部变量、当前执行到的指令的编号。
以如下代码为例:
def foo(x, y=1):
z = x + y
return z*2
foo(2, 3)
其编译后的字节码为
1 0 LOAD_CONST 6 ((1,))
2 LOAD_CONST 1 (<code object foo at 0x000002511F5B4F50, file "<dis>", line 1>)
4 LOAD_CONST 2 ('foo')
6 MAKE_FUNCTION 1 (defaults)
8 STORE_NAME 0 (foo)
5 10 LOAD_NAME 0 (foo)
12 LOAD_CONST 3 (2)
14 LOAD_CONST 4 (3)
16 CALL_FUNCTION 2
18 POP_TOP
20 LOAD_CONST 5 (None)
22 RETURN_VALUE
Disassembly of <code object foo at 0x000002511F5B4F50, file "<dis>", line 1>:
2 0 LOAD_FAST 0 (x)
2 LOAD_FAST 1 (y)
4 BINARY_ADD
6 STORE_FAST 2 (z)
3 8 LOAD_FAST 2 (z)
10 LOAD_CONST 1 (2)
12 BINARY_MULTIPLY
14 RETURN_VALUE
PyCodeObject、PyFunctionObject、PyFrameObject三者的关系如下:

PyCodeObject在编译时确定,PyFunctionObject和PyFrameObject都在运行时生成。
其中PyFunctionObject在执行到函数定义指令MAKE_FUNCTION时生成,生成后是静态不变的。也就是说,一个函数一旦定义,其函数名参数默认值、函数绑定的globals和builtins信息不再变化。
PyFrameObject是动态可变的,其包含两层含义:
1)对同一个函数的每一次函数,都会生成一个新的PyFrameObject;
2)每个PyFrameObject在其生命周期内也是不断发生变化的,PyFrameObject承载着函数执行时所需要的所有动态信息。
MAKE_FUNCTION创建PyFunctionObject的过程:
// 创建PyFunctionObject
PyObject *
PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
{
// 获取解释器状态
PyThreadState *tstate = _PyThreadState_GET();
// 获取PyCodeObject
PyCodeObject *code_obj = (PyCodeObject *)code;
// 获取name和const
PyObject *name = code_obj->co_name;
if (!qualname) {
qualname = name;
}
PyObject *consts = code_obj->co_consts;
// 获取函数所属的__module__
// __module__: Use globals['__name__'] if it exists, or NULL.
PyObject *module = _PyDict_GetItemIdWithError(globals, &PyId___name__);
// 优先从globals中获取builtins,找不到则从当前栈帧中找,还找不到则以Python解释器中初始化定义的builtins为准
PyObject *builtins = NULL;
builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref
// 创建函数对象
PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
// 设置参数
op->func_globals = globals;
op->func_builtins = builtins;
op->func_name = name;
op->func_qualname = qualname;
op->func_code = (PyObject*)code_obj;
op->func_defaults = NULL; // No default positional arguments
op->func_kwdefaults = NULL; // No default keyword arguments
op->func_closure = NULL;
op->func_dict = NULL;
op->func_weakreflist = NULL;
op->func_module = module;
op->func_annotations = NULL;
// Python函数调用的实现对应的C函数
op->vectorcall = _PyFunction_Vectorcall;
return (PyObject *)op;
}
CALL_FUNCTION执行函数过程:
// python函数调用
PyObject *
_PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con,
PyObject *locals,
PyObject* const* args, size_t argcount,
PyObject *kwnames)
{
// 创建栈帧
PyFrameObject *f = _PyEval_MakeFrameVector(
tstate, con, locals, args, argcount, kwnames);
// 执行栈帧
PyObject *retval = _PyEval_EvalFrame(tstate, f, 0);
return retval;
}
static inline PyObject*
_PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
{
return tstate->interp->eval_frame(tstate, f, throwflag);
}
// 执行栈帧的实现
// 解释的eval_frame在解释器初始化时就设置成了_PyEval_EvalFrameDefault
PyObject* _Py_HOT_FUNCTION
_PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
{
// 连接到前一帧
CFrame *prev_cframe = tstate->cframe;
// 切换当前帧
tstate->frame = f;
PyCodeObject *co = f->f_code;
first_instr = (_Py_CODEUNIT *) PyBytes_AS_STRING(co->co_code);
next_instr = first_instr + f->f_lasti + 1;
for (;;) {
_Py_CODEUNIT word = *next_instr;
opcode = _Py_OPCODE(word);
oparg = _Py_OPARG(word);
next_instr++;
switch (opcode) {
// 执行字节码
}
}
}
浙公网安备 33010602011771号