当前位置:   article > 正文

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

pycfunction_fastcallkeywords

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

def fun():
    return 1
fun()
  • 1
  • 2
  • 3
  • 4

看一下字节码:

              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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

前半段和上节一样,定义了一个函数,然后加载名字“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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

第一行

PyObject **pfunc = (*pp_stack) - oparg - 1;
  • 1

获取了函数对象,这个算式很明显,就是栈顶指针减去参数个数再-1就得到了指向函数对象的地址的栈元素。
然后

if (PyCFunction_Check(func)) 
  • 1

判断是不是C函数,很明显,我们是自定义的函数,跳过。
还有个判断

 if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) 
  • 1

方法判断,也就是是不是属于某个类啥的,也跳过
最后来到这:

if (PyFunction_Check(func)) {
            x = fast_function(func, stack, nargs, kwnames);
        }
  • 1
  • 2
  • 3

转眼进入了另外一个函数,然后进行了一系列的名字空间和栈的处理后,就递归回了PyEval_EvalFrameEx继续字节码循环处理。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/199172
推荐阅读
相关标签
  

闽ICP备14008679号