• Python中PyCodeObject、PyFunctionObject、PyFrameObject的区别与联系


    PyCodeObject:代码对象,就是一段代码编译后形成的对象,函数中对应的就是函数体的代码编译结果。

    PyFunctionObject :函数对象,它是对PyCodeObject的封装,相当于 PyCodeObject + 函数def定义这一行代码。它在PyCodeObject基础上增加了函数的名称、所属的模块、参数默认值、globals、builtins。

    PyFrameObject:函数执行时对应的栈帧,它用于承载PyFunctionObject在执行时所需要的动态信息。包括函数的实参、函数执行时所需的栈、全局变量、局部变量、当前执行到的指令的编号。

    以如下代码为例:

    def foo(x, y=1):
        z = x + y
        return z*2
    
    foo(2, 3)
    

      

    其编译后的字节码为

      1           0 LOAD_CONST               6 ((1,))
                  2 LOAD_CONST               1 (<code object foo at 0x000002511F5B4F50, file "<dis>", line 1>)
                  4 LOAD_CONST               2 ('foo')
                  6 MAKE_FUNCTION            1 (defaults)
                  8 STORE_NAME               0 (foo)
      5          10 LOAD_NAME                0 (foo)
                 12 LOAD_CONST               3 (2)
                 14 LOAD_CONST               4 (3)
                 16 CALL_FUNCTION            2
                 18 POP_TOP
                 20 LOAD_CONST               5 (None)
                 22 RETURN_VALUE
    Disassembly of <code object foo at 0x000002511F5B4F50, file "<dis>", line 1>:
      2           0 LOAD_FAST                0 (x)
                  2 LOAD_FAST                1 (y)
                  4 BINARY_ADD
                  6 STORE_FAST               2 (z)
      3           8 LOAD_FAST                2 (z)
                 10 LOAD_CONST               1 (2)
                 12 BINARY_MULTIPLY
                 14 RETURN_VALUE
    

      

     PyCodeObject、PyFunctionObject、PyFrameObject三者的关系如下:

    PyCodeObject在编译时确定,PyFunctionObject和PyFrameObject都在运行时生成。

    其中PyFunctionObject在执行到函数定义指令MAKE_FUNCTION时生成,生成后是静态不变的。也就是说,一个函数一旦定义,其函数名参数默认值、函数绑定的globals和builtins信息不再变化。

    PyFrameObject是动态可变的,其包含两层含义:

    1)对同一个函数的每一次函数,都会生成一个新的PyFrameObject;

    2)每个PyFrameObject在其生命周期内也是不断发生变化的,PyFrameObject承载着函数执行时所需要的所有动态信息。

    MAKE_FUNCTION创建PyFunctionObject的过程:

    // 创建PyFunctionObject
    PyObject *
    PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
    {
    	// 获取解释器状态
        PyThreadState *tstate = _PyThreadState_GET();
    	// 获取PyCodeObject
        PyCodeObject *code_obj = (PyCodeObject *)code;
    	// 获取name和const
        PyObject *name = code_obj->co_name;
        if (!qualname) {
            qualname = name;
        }
        PyObject *consts = code_obj->co_consts;
    	// 获取函数所属的__module__
        // __module__: Use globals['__name__'] if it exists, or NULL.
        PyObject *module = _PyDict_GetItemIdWithError(globals, &PyId___name__);
        // 优先从globals中获取builtins,找不到则从当前栈帧中找,还找不到则以Python解释器中初始化定义的builtins为准
        PyObject *builtins = NULL;
        builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref
        // 创建函数对象
        PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
        // 设置参数
        op->func_globals = globals;
        op->func_builtins = builtins;
        op->func_name = name;
        op->func_qualname = qualname;
        op->func_code = (PyObject*)code_obj;
        op->func_defaults = NULL;    // No default positional arguments
        op->func_kwdefaults = NULL;  // No default keyword arguments
        op->func_closure = NULL;
        op->func_dict = NULL;
        op->func_weakreflist = NULL;
        op->func_module = module;
        op->func_annotations = NULL;
        // Python函数调用的实现对应的C函数
        op->vectorcall = _PyFunction_Vectorcall;
        return (PyObject *)op;
    }
    

    CALL_FUNCTION执行函数过程:

    // python函数调用
    PyObject *
    _PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con,
                   PyObject *locals,
                   PyObject* const* args, size_t argcount,
                   PyObject *kwnames)
    {
        // 创建栈帧
        PyFrameObject *f = _PyEval_MakeFrameVector(
            tstate, con, locals, args, argcount, kwnames);
        // 执行栈帧
        PyObject *retval = _PyEval_EvalFrame(tstate, f, 0);
        return retval;
    }
    
    static inline PyObject*
    _PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
    {
        return tstate->interp->eval_frame(tstate, f, throwflag);
    }
    
    // 执行栈帧的实现
    // 解释的eval_frame在解释器初始化时就设置成了_PyEval_EvalFrameDefault
    PyObject* _Py_HOT_FUNCTION
    _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
    {
        // 连接到前一帧
    	CFrame *prev_cframe = tstate->cframe;
        // 切换当前帧
        tstate->frame = f;
        PyCodeObject *co = f->f_code;
        first_instr = (_Py_CODEUNIT *) PyBytes_AS_STRING(co->co_code);
        next_instr = first_instr + f->f_lasti + 1;
        
        for (;;) {
            _Py_CODEUNIT word = *next_instr; 
            opcode = _Py_OPCODE(word); 
            oparg = _Py_OPARG(word); 
            next_instr++; 
            switch (opcode) {
                // 执行字节码
            }
        }
    }
    

      

  • 相关阅读:
    源码解析.Net中IConfiguration配置的实现
    python小工具
    hue搭建以及报错记录
    jenkins启动指定数据目录
    基于三维地图的智慧园区可视化解决方案
    工业4.0的下一个十年
    项目管理知识体系介绍
    人工智能发展的新方向
    速成财务产品经理
    标准化体系:运营—训练—督导
  • 原文地址:https://www.cnblogs.com/tuzkee/p/15917023.html
Copyright © 2020-2023  润新知