函数,是一个动态的过程,在函数被调用时,系统会动态创建一个栈帧,函数对应的表示结构:
typedef struct {
PyObject_HEAD
PyObject *func_code; /* A code object */
PyObject *func_globals; /* 函数运行时的global名称空间 */
PyObject *func_defaults; /* 函数默认参数 NULL or a tuple */
PyObject *func_closure; // 用于实现闭包的
PyObject *func_doc; /* The __doc__ attribute, can be anything */
PyObject *func_name; /* The __name__ attribute, a string object */
PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */
PyObject *func_weakreflist; /* List of weak references */
PyObject *func_module; /* The __module__ attribute, can be anything */
} PyFunctionObject;
函数内包含的func_code则对应的是函数的代码,静态的、在编译时就定义好了,而函数则是在运行时,即运行到def语句时构建(func_globals是在这时候才能确定的)
所以,一段代码肯定对应一个code object,但是函数对象可能有多个,例如多次调用该函数,会构建多个func object,这些func object的func_code都指向一个code object。
函数对象的创建
注意,Python在执行到def语句后,接着执行其后的代码,而不是进入到函数体内执行其中的语句(这些语句是在编译时就已经构建好了对应的code object),函数的声明和实现时分离的,分在了不同的code object中。
def语句
对应的机器码有三条:
load_const 0
装载编译好的函数体的code object
make_function
构建函数对象
store_name 0
把构建好的函数对象添加到名称空间内
make_function
pop
把之前装载的函数体的code object取出来
PyFunction_New(v, f->f_globals)
主要是分配函数对象的空间,给函数对象中的func_code, func_globals等赋值。
push
把创建好的函数对象压入运行时栈中,最后通过store_name添加。
函数调用
f()
对应的机器码五条:
load_name 0
获取该函数对象
call_function 0
调用
pop_top
load_const
return_value
返回值