python3.6 源码分析(四):函数调用

上一节定义了函数,这节趁热打铁,看一下函数调用的过程。

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继续字节码循环处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值