当前位置: 首页 > news >正文

用自己点电脑做电影网站建设通网站免费注册

用自己点电脑做电影网站,建设通网站免费注册,免费平台源码资源网,电子商务网站建设考卷栈帧#xff08;Stack Frame#xff09;是 Python 虚拟机中程序执行的载体之一#xff0c;也是 Python 中的一种执行上下文。每当 Python 执行一个函数或方法时#xff0c;都会创建一个栈帧来表示当前的函数调用#xff0c;并将其压入一个称为调用栈#xff08;Call Stac…栈帧Stack Frame是 Python 虚拟机中程序执行的载体之一也是 Python 中的一种执行上下文。每当 Python 执行一个函数或方法时都会创建一个栈帧来表示当前的函数调用并将其压入一个称为调用栈Call Stack的数据结构中。调用栈是一个后进先出LIFO的数据结构用于管理程序中的函数调用关系。 栈帧的创建和销毁是动态的随着函数的调用和返回而不断发生。当一个函数被调用时一个新的栈帧会被创建并推入调用栈当函数调用结束后对应的栈帧会从调用栈中弹出并销毁。 栈帧的使用使得 Python 能够实现函数的嵌套调用和递归调用。通过不断地创建和销毁栈帧Python 能够跟踪函数调用关系保存和恢复局部变量的值实现函数的嵌套和递归执行。同时栈帧还可以用于实现异常处理、调试信息的收集和优化技术等。 需要注意的是栈帧是有限制的Python 解释器会对栈帧的数量和大小进行限制以防止栈溢出和资源耗尽的情况发生。在编写 Python 程序时合理使用函数调用和栈帧可以帮助提高程序的性能和可维护性。 栈帧数据结构 typedef struct _frame {PyObject_VAR_HEADstruct _frame *f_back; /* previous frame, or NULL */PyCodeObject *f_code; /* code segment */PyObject *f_builtins; /* builtin symbol table (PyDictObject) */PyObject *f_globals; /* global symbol table (PyDictObject) */PyObject *f_locals; /* local symbol table (any mapping) */PyObject **f_valuestack; /* points after the last local *//* Next free slot in f_valuestack. Frame creation sets to f_valuestack.Frame evaluation usually NULLs it, but a frame that yields sets itto the current stack top. */PyObject **f_stacktop;PyObject *f_trace; /* Trace function *//* In a generator, we need to be able to swap between the exceptionstate inside the generator and the exception state of the callingframe (which shouldnt be impacted when the generator yieldsfrom an except handler).These three fields exist exactly for that, and are unused fornon-generator frames. See the save_exc_state and swap_exc_statefunctions in ceval.c for details of their use. */PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;/* Borrowed reference to a generator, or NULL */PyObject *f_gen;int f_lasti; /* Last instruction if called *//* Call PyFrame_GetLineNumber() instead of reading this fielddirectly. As of 2.3 f_lineno is only valid when tracing isactive (i.e. when f_trace is set). At other times we usePyCode_Addr2Line to calculate the line from the currentbytecode index. */int f_lineno; /* Current line number */int f_iblock; /* index in f_blockstack */char f_executing; /* whether the frame is still executing */PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */PyObject *f_localsplus[1]; /* localsstack, dynamically sized */} PyFrameObject; 内存申请和栈帧的内存布局 在 cpython 当中当我们需要申请一个 frame object 对象的时候首先需要申请内存空间但是在申请内存空间的时候并不是单单申请一个 frameobject 大小的内存而是会申请额外的内存空间大致布局如下所示。 f_localsplus这是一个数组用户保存函数执行的 local 变量这样可以直接通过下标得到对应的变量的值。ncells 和 nfrees这个变量和我们前面在分析 code object 的函数闭包相关ncells 和 ncells 分别表示 cellvars 和 freevars 中变量的个数。stack这个变量就是函数执行的时候函数的栈帧这个大小在编译期间就可以确定因此可以直接确定栈空间的大小。 下面是在申请 frame object 的核心代码 Py_ssize_t extras, ncells, nfrees;ncells PyTuple_GET_SIZE(code-co_cellvars); // 得到 co_cellvars 当中元素的个数 没有的话则是 0nfrees PyTuple_GET_SIZE(code-co_freevars); // 得到 co_freevars 当中元素的个数 没有的话则是 0// extras 就是表示除了申请 frame object 自己的内存之后还需要额外申请多少个 指针对象// 确切的带来说是用于保存 PyObject 的指针extras code-co_stacksize code-co_nlocals ncells nfrees;if (free_list NULL) {f PyObject_GC_NewVar(PyFrameObject, PyFrame_Type,extras);if (f NULL) {Py_DECREF(builtins);return NULL;}}// 这个就是函数的 code object 对象 将其保存到栈帧当中 f 就是栈帧对象f-f_code code;extras code-co_nlocals ncells nfrees;// 这个就是栈顶的位置 注意这里加上的 extras 并不包含栈的大小f-f_valuestack f-f_localsplus extras;// 对额外申请的内存空间尽心初始化操作for (i0; iextras; i)f-f_localsplus[i] NULL;f-f_locals NULL;f-f_trace NULL;f-f_exc_type f-f_exc_value f-f_exc_traceback NULL;f-f_stacktop f-f_valuestack; // 将栈顶的指针指向栈的起始位置f-f_builtins builtins;Py_XINCREF(back);f-f_back back;Py_INCREF(code);Py_INCREF(globals);f-f_globals globals;/* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */if ((code-co_flags (CO_NEWLOCALS | CO_OPTIMIZED)) (CO_NEWLOCALS | CO_OPTIMIZED)); /* f_locals NULL; will be set by PyFrame_FastToLocals() */else if (code-co_flags CO_NEWLOCALS) {locals PyDict_New();if (locals NULL) {Py_DECREF(f);return NULL;}f-f_locals locals;}else {if (locals NULL)locals globals;Py_INCREF(locals);f-f_locals locals;}f-f_lasti -1;f-f_lineno code-co_firstlineno;f-f_iblock 0;f-f_executing 0;f-f_gen NULL; 现在我们对 frame object 对象当中的各个字段进行分析说明他们的作用 PyObject_VAR_HEAD表示对象的头部信息包括引用计数和类型信息。f_back前一个栈帧对象的指针或者为NULL。f_code指向 PyCodeObject 对象的指针表示当前帧执行的代码段。f_builtins指向 PyDictObject 对象的指针表示当前帧的内置符号表字典对象键是字符串值是对应的 python 对象。f_globals指向 PyDictObject 对象的指针表示当前帧的全局符号表。f_locals指向任意映射对象的指针表示当前帧的局部符号表。f_valuestack指向当前帧的值栈底部的指针。f_stacktop指向当前帧的值栈顶部的指针。f_trace指向跟踪函数对象的指针用于调试和追踪代码执行过程这个字段我们在后面的文章当中再进行分析。f_exc_type、f_exc_value、f_exc_traceback这个字段和异常相关在函数执行的时候可能会产生错误异常这个就是用于处理异常相关的字段。f_gen指向当前生成器对象的指针如果当前帧不是生成器则为NULL。f_lasti上一条指令在字节码当中的下标。f_lineno当前执行的代码行号。f_iblock当前执行的代码块在f_blockstack中的索引这个字段也主要和异常的处理有关系。f_executing表示当前帧是否仍在执行。f_blockstack用于try和loop代码块的堆栈最多可以嵌套 CO_MAXBLOCKS 层。f_localsplus局部变量和值栈的组合是一个动态大小的数组。 如果我们在一个函数当中调用另外一个函数这个函数再调用其他函数就会形成函数的调用链就会形成下图所示的链式结构。 例子分析 我们现在来模拟一下下面的函数的执行过程。 import disdef foo():a 1b 2return a bif __name__ __main__:dis.dis(foo)print(foo.__code__.co_stacksize)foo() 上面的 foo 函数的字节码如下所示 6 0 LOAD_CONST 1 (1)2 STORE_FAST 0 (a)7 4 LOAD_CONST 2 (2)6 STORE_FAST 1 (b)8 8 LOAD_FAST 0 (a)10 LOAD_FAST 1 (b)12 BINARY_ADD14 RETURN_VALUE 函数 foo 的 stacksize 等于 2 。 初始时 frameobject 的布局如下所示 现在执行第一条指令 LOAD_CONST 此时的 f_lasti 等于 -1执行完这条字节码之后栈帧情况如下 在执行完这条字节码之后 f_lasti 的值变成 0。字节码 LOAD_CONST 对应的 c 源代码如下所示 TARGET(LOAD_CONST) {PyObject *value GETITEM(consts, oparg); // 从常量表当中取出下标为 oparg 的对象Py_INCREF(value);PUSH(value);FAST_DISPATCH();} 首先是从 consts 将对应的常量拿出来然后压入栈空间当中。 再执行 STORE_FAST 指令这个指令就是将栈顶的元素弹出然后保存到前面提到的 f_localsplus 数组当中去那么现在栈空间是空的。STORE_FAST 对应的 c 源代码如下 TARGET(STORE_FAST) {PyObject *value POP(); // 将栈顶元素弹出SETLOCAL(oparg, value); // 保存到 f_localsplus 数组当中去FAST_DISPATCH();} 执行完这条指令之后 f_lasti 的值变成 2 。 接下来的两条指令和上面的一样就不做分析了在执行完两条指令f_lasti 变成 6 。 接下来两条指令分别将 a b 加载进入栈空间单中现在栈空间布局如下所示 然后执行 BINARY_ADD 指令 弹出栈空间的两个元素并且把他们进行相加操作最后将得到的结果再压回栈空间当中。 TARGET(BINARY_ADD) {PyObject *right POP();PyObject *left TOP();PyObject *sum;if (PyUnicode_CheckExact(left) PyUnicode_CheckExact(right)) {sum unicode_concatenate(left, right, f, next_instr);/* unicode_concatenate consumed the ref to left */}else {sum PyNumber_Add(left, right);Py_DECREF(left);}Py_DECREF(right);SET_TOP(sum); // 将结果压入栈中if (sum NULL)goto error;DISPATCH();} 最后执行 RETURN_VALUE 指令将栈空间结果返回。 总结 在本篇文章当中主要介绍了 cpython 当中的函数执行的时候的栈帧结构这里面包含的程序执行时候所需要的一些必要的变量比如说全局变量python 内置的一些对象等等同时需要注意的是 python 在查询对象的时候如果本地 f_locals 没有找到就会去全局 f_globals 找如果还没有找到就会去 f_builtins 里面的找当一个程序返回的时候就会找到 f_back 他上一个执行的栈帧将其设置成当前线程正在使用的栈帧这就完成了函数的调用返回关于这个栈帧还有一些其他的字段我们没有谈到在后续的文章当中将继续深入其中一些字段。
http://www.zqtcl.cn/news/985730/

相关文章:

  • 淮南建设网站菏泽兼职网站建设
  • 品牌做网站公司做网站需要一些什么东西
  • 网页制作软件三剑客网站优化排名的方法
  • 购物网站开发背景及目的做百度推广网站咱们做
  • 漳州最专业的网站建设公司网站建设工作方案
  • 江西省建设厅网站官网网站备案期间可以用二级域名访问网站吗
  • 三丰云做网站步骤php网站建设视频教程
  • 赤峰网站开发公司wordpress电子商务主题 中文
  • 网站建设运营工作业绩怎样查看网站备案号
  • 江苏常州网站建设公司外贸网站建设盲区
  • 响应式网站设计教程wordpress 医院主题
  • 手机上怎么上传网站吗舟山做网站
  • 程序员做个网站要多少钱呢网站开发设计技术路线
  • 企业网站优化与推广哪个网站seo做的最好
  • 学做网站 软件合肥市建设投资有限公司
  • 网站开发优势用php制作一个个人信息网站
  • wordpress百度推送代码兰州网站关键字优化
  • 有了域名怎么建设网站在线crm免费将夜2
  • 网站建设 技术方案模板长沙手机网站公司
  • 游戏网站建设免费版百度只更新快照不收录网站
  • html小清新类型网站网站建设中应注意哪些问题
  • 网站开发技术和seo的联系精品课程网站建设 公司
  • 大型网站建设一般多少钱wordpress 调用百度前端公众库
  • 个人电脑做网站服务器网站地方网站域名用全拼
  • 我们网站在那里登陆后台系统管理成都app制作开发
  • 可以做问卷调查的网站仙居网站建设
  • 知名网站建设公司电话做一个小程序需要多少钱
  • 外贸找客户有什么网站个人如何做网站
  • 旅游项目网站开发ui界面设计分析
  • 企业建设网站没有服务器代理网页浏览