赞
踩
上一节定义了函数,这节趁热打铁,看一下函数调用的过程。
def fun():
return 1
fun()
看一下字节码:
0 LOAD_CONST 0 (<code object fun at 0x0000021461E68ED0, file "", line 1>)
2 LOAD_CONST 1 ('fun')
4 MAKE_FUNCTION 0
6 STORE_NAME 0 (fun)
8 LOAD_NAME 0 (fun)
10 CALL_FUNCTION 0
12 POP_TOP
前半段和上节一样,定义了一个函数,然后加载名字“fun”,执行了CALL_FUNCTION这条字节码,紧接着POP_TOP,因为我们写的例子程序里面函数的返回值是被丢弃了的,所以要从栈顶弹出,不然会破坏栈结构,程序分分钟扑街。
好了,直接看CALL_FUNCTION的实现吧:
完整代码
static PyObject *
call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
{
PyObject **pfunc = (*pp_stack) - oparg - 1;
PyObject *func = *pfunc;
PyObject *x, *w;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
Py_ssize_t nargs = oparg - nkwargs;
PyObject **stack;
/* Always dispatch PyCFunction first, because these are
presumed to be the most frequent callable object.
*/
if (PyCFunction_Check(func)) {
PyThreadState *tstate = PyThreadState_GET();
PCALL(PCALL_CFUNCTION);
stack = (*pp_stack) - nargs - nkwargs;
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
}
else {
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
/* optimize access to bound methods */
PyObject *self = PyMethod_GET_SELF(func);
PCALL(PCALL_METHOD);
PCALL(PCALL_BOUND_METHOD);
Py_INCREF(self);
func = PyMethod_GET_FUNCTION(func);
Py_INCREF(func);
Py_SETREF(*pfunc, self);
nargs++;
}
else {
Py_INCREF(func);
}
stack = (*pp_stack) - nargs - nkwargs;
if (PyFunction_Check(func)) {
x = fast_function(func, stack, nargs, kwnames);
}
else {
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
}
Py_DECREF(func);
}
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
/* Clear the stack of the function object. Also removes
the arguments in case they weren't consumed already
(fast_function() and err_args() leave them on the stack).
*/
while ((*pp_stack) > pfunc) {
w = EXT_POP(*pp_stack);
Py_DECREF(w);
PCALL(PCALL_POP);
}
return x;
}
第一行
PyObject **pfunc = (*pp_stack) - oparg - 1;
获取了函数对象,这个算式很明显,就是栈顶指针减去参数个数再-1就得到了指向函数对象的地址的栈元素。
然后
if (PyCFunction_Check(func))
判断是不是C函数,很明显,我们是自定义的函数,跳过。
还有个判断
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL)
方法判断,也就是是不是属于某个类啥的,也跳过
最后来到这:
if (PyFunction_Check(func)) {
x = fast_function(func, stack, nargs, kwnames);
}
转眼进入了另外一个函数,然后进行了一系列的名字空间和栈的处理后,就递归回了PyEval_EvalFrameEx继续字节码循环处理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。