从函数内函数定义看python的函数实现
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了从函数内函数定义看python的函数实现,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含2368字,纯文字阅读大概需要4分钟。
内容图文
一、问题
在C/C++中,函数的定义本质上是在编译阶段完成,而函数调用是由链接完成。但是对于python这种语言,函数的定义和调用都是由解释器在运行时完成,或者说,解释器在执行函数定义的时候,同样是生成了虚拟机指令,这个指令通常可以理解为MAKE_FUNCTION这个虚拟机指令,这个指令生成的则是一个PyFunctionObject对象。对应的,在函数调用的时候执行的是CALL_FUNCTION,这个指令需要生成一个PyFrameObject对象。
二、CALL_FUNCTION的执行
1、函数的调用
一个函数的构成。静态代码信息大致对应函数模版,也就是函数本身的描述信息:例如函数的虚拟机指令集合、使用的常量、使用的自由变量数量、局部变量数量等信息。但是,函数执行时候,最为关键的是需要一个栈信息,这个是函数的动态特性。如果一个函数需要在多线程中运行,那么它必须有自己私有的堆栈信息。
可以看到,在执行CALL_FUNCTION指令时,会动态创建一个PyFrameObject对象,这个变量从名字上看就可以知道它对于保存局部变量有着责无旁贷的义务。
static PyObject *
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject **args, Py_ssize_t argcount,
PyObject **kwnames, PyObject **kwargs,
Py_ssize_t kwcount, int kwstep,
PyObject **defs, Py_ssize_t defcount,
PyObject *kwdefs, PyObject *closure,
PyObject *name, PyObject *qualname)
{
……
assert(tstate != NULL);
f = PyFrame_New(tstate, co, globals, locals);
……
}
2、堆栈的生成
那么一个函数运行时堆栈中使用的临时变量存储在哪里呢?
在调用PyObject_GC_NewVar的时候,额外要求在PyFrameObject结构之后分配extras个Object对象,这个extras包含了堆栈大小,局部变量、cell变量和free变量,一个函数的运行时信息就存储在这里,它的基地址由f_localsplus执行。从实现上看,f_localsplus定义为
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
它定义在函数的最后,从而对象创建之后,这个变量就自动指向了额外变量
PyFrameObject *
PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
PyObject *locals)
{
……
Py_ssize_t extras, ncells, nfrees;
ncells = PyTuple_GET_SIZE(code->co_cellvars);
nfrees = PyTuple_GET_SIZE(code->co_freevars);
extras = code->co_stacksize + code->co_nlocals + ncells +
nfrees;
if (free_list == NULL) {
f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type,
extras);
……
f->f_code = code;
extras = code->co_nlocals + ncells + nfrees;
f->f_valuestack = f->f_localsplus + extras;
for (i=0; i<extras; 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;
……
}
三、一个推论
既然函数定义也有对应的机器指令,那么如果一个函数中嵌套了另一个函数定义,在执行外层函数的时候,内层函数的定义依然会被执行。并且由于两次执行的栈帧不同,所以每次执行都会由MAKE_FUNCTION生成新的函数对象。我们可以通过下面的代码验证一下,可以看到返回的两个内部函数定义并不相同,虽然逻辑上看是相同的函数。
tsecer@harry: cat innerdef.py
def outter():
def inner():
print("something")
return inner
inner1 =outter()
inner2 = outter()
print(inner1, inner2)
tsecer@harry: python innerdef.py
(<function inner at 0x7f6e6b5015f0>, <function inner at 0x7f6e6b501668>)
tsecer@harry:
原文:https://www.cnblogs.com/tsecer/p/10382793.html
内容总结
以上是互联网集市为您收集整理的从函数内函数定义看python的函数实现全部内容,希望文章能够帮你解决从函数内函数定义看python的函数实现所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。