python定义函数的语句十分简单:
0 LOAD_CONST 0 (<code object fun at 0x000001C7DFA48ED0, file "", line 1>)
2 LOAD_CONST 1 ('fun')
4 MAKE_FUNCTION 0
6 STORE_NAME 0 (fun)
首先加载codeobject到栈顶,然后加载函数名,MAKE_FUNCTION就完了,这看似简单的背后其实python做了大量的工作,一方面是函数内的语句的编译,还有就是各种名字空间的绑定,比如闭包。
让我们通过python源码看看函数究竟是怎么构造出来的,从MAKE_FUNCTION入手看看这条字节码的实现:
TARGET(MAKE_FUNCTION) {
PyObject *qualname = POP();
PyObject *codeobj = POP();
PyFunctionObject *func = (PyFunctionObject *)
PyFunction_NewWithQualName(codeobj, f->f_globals, qualname);
Py_DECREF(codeobj);
Py_DECREF(qualname);
if (func == NULL) {
goto error;
}
if (oparg & 0x08) {
assert(PyTuple_CheckExact(TOP()));
func ->func_closure = POP();
}
if (oparg & 0x04) {
assert(PyDict_CheckExact(TOP()));
func->func_annotations = POP();
}
if (oparg & 0x02) {
assert(PyDict_CheckExact(TOP()));
func->func_kwdefaults = POP();
}
if (oparg & 0x01) {
assert(PyTuple_CheckExact(TOP()));
func->func_defaults = POP();
}
PUSH((PyObject *)func);
DISPATCH();
}
先不看那些if判断,主要的流程就是PyFunction_NewWithQualName这个函数了,至于那些if,初步判断应该是根据MAKE_FUNCTION的参数取栈顶数据函数对象相应的域,具体是什么目前不得而知。
好吧,先看PyFunction_NewWithQualName:
PyObject *
PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
{
PyFunctionObject *op;
PyObject *doc, *consts, *module;
static PyObject *__name__ = NULL;
if (__name__ == NULL) {
__name__ = PyUnicode_InternFromString("__name__");
if (__name__ == NULL)
return NULL;
}
op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
if (op == NULL)
return NULL;
op->func_weakreflist = NULL;
Py_INCREF(code);
op->func_code = code;
Py_INCREF(globals);
op->func_globals = globals;
op->func_name = ((PyCodeObject *)code)->co_name;
Py_INCREF(op->func_name);
op->func_defaults = NULL; /* No default arguments */
op->func_kwdefaults = NULL; /* No keyword only defaults */
op->func_closure = NULL;
consts = ((PyCodeObject *)code)->co_consts;
if (PyTuple_Size(consts) >= 1) {
doc = PyTuple_GetItem(consts, 0);
if (!PyUnicode_Check(doc))
doc = Py_None;
}
else
doc = Py_None;
Py_INCREF(doc);
op->func_doc = doc;
op->func_dict = NULL;
op->func_module = NULL;
op->func_annotations = NULL;
/* __module__: If module name is in globals, use it.
Otherwise, use None. */
module = PyDict_GetItem(globals, __name__);
if (module) {
Py_INCREF(module);
op->func_module = module;
}
if (qualname)
op->func_qualname = qualname;
else
op->func_qualname = op->func_name;
Py_INCREF(op->func_qualname);
_PyObject_GC_TRACK(op);
return (PyObject *)op;
}
当然这么长的代码考虑到了定义函数的所有情况,而我们只是定义了一个最简单的无参函数,所以最重要的无非是code和globals这两个域了,看看他们的出处,code不用说了,就是函数体编译成的codeobejct,那么globals呢,我们往上回溯,参数来自f->f_globals这个东西,再往上找f的定义,
_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
其实就是当前栈帧咯,也就是说,定义一个函数,这个函数的globals名字空间就是当前栈帧的名字空间,以后不论函数在哪里被调用,都能访问到当前globals下的名字,厉害吧。。。。