标签:style class blog code http tar
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie
1.Python虚拟机在执行函数调用时会动态地创建新的 PyFrameObject对象,
这些PyFrameObject对象之间会形成PyFrameObject对象链,模拟x86平台上运行时栈
2.PyFuctionObject对象
typedef struct { PyObject_HEAD PyObject *func_code; //对应函数编译后的PyCodeObject对象 PyObject *func_globals; //函数运行时的global空间 PyObject *func_defaults; //默认参数(tuple或NULL) PyObject *func_closure; //NULL or a tuple of cell objects,用于实现closure PyObject *func_doc; //函数的文档(PyStringObject) PyObject *func_name; //函数名称,函数的__name__属性,(PyStringObject) PyObject *func_dict; //函数的__dict__属性(PyDictObject或NULL) PyObject *func_weakreflist; PyObject *func_module; //函数的__module__,可以是任何对象 } PyFunctionObject;
def f(): #LOAD_CONST 0 #MAKE_FUNCTION 0 #STORE_NAME 0 print "Function" #LOAD_CONST 1 #PRINT_ITEM #PRINT_NEWLINE #LOAD_CONST #RETURN_VALUE f() #LOAD_NAME 0 #CALL_FUNCTION 0 #POP_TOP #LOAD_CONST 1 #RETURN_VALUE
def f()创建了函数对象,如图11-6所示
call_function函数调用
static PyObject * call_function(PyObject ***pp_stack, int oparg #ifdef WITH_TSC , uint64* pintr0, uint64* pintr1 #endif ) { //[1]:处理函数参数信息 int na = oparg & 0xff; //位置参数、扩展位置参数个数 int nk = (oparg>>8) & 0xff; //键参数、扩展键参数个数 int n = na + 2 * nk; //总共的参数个数 nk*2是因为(键,值)对中键和值各占一个位置 //[2]:获得PyFunctionObject对象 PyObject **pfunc = (*pp_stack) - n - 1; PyObject *func = *pfunc; PyObject *x, *w; if (PyCFunction_Check(func) && nk == 0) { //... } else { if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { } else //[3]:对PyFunctionObject对象进行调用 if (PyFunction_Check(func)) x = fast_function(func, pp_stack, n, na, nk); else x = do_call(func, pp_stack, na, nk); //... } //... return x; }
static PyObject * fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) { PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); PyObject *globals = PyFunction_GET_GLOBALS(func); PyObject *argdefs = PyFunction_GET_DEFAULTS(func); PyObject **d = NULL; int nd = 0; //... //[1]:一般函数的快速通道 if (argdefs == NULL && co->co_argcount == n && nk==0 && co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { PyFrameObject *f; PyObject *retval = NULL; PyThreadState *tstate = PyThreadState_GET(); PyObject **fastlocals, **stack; int i; f = PyFrame_New(tstate, co, globals, NULL); //... retval = PyEval_EvalFrameEx(f,0); //... return retval; } if (argdefs != NULL) { d = &PyTuple_GET_ITEM(argdefs, 0); nd = Py_SIZE(argdefs); } return PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, (*pp_stack)-n, na, (*pp_stack)-2*nk, nk, d, nd, PyFunction_GET_CLOSURE(func)); }
def fun(a, b): pass fun(1, b = 2)
def f(name, age): #LOAD_CONST 0 #MAKE_FUNCTION 0 #STORE_NAME 0 age += 5 #LOAD_FAST 1 #LOAD_CONST 5 #INPLACE_ADD #STORE_FAST 1 print "[", name, ",", age, "]" #LOAD_CONST 2 #PRINT_ITEM #LOAD_FAST 0 #PRINT_ITEM #LOAD_CONST 3 #PRINT_ITEM #LOAD_FAST 1 #PRINT_ITEM #LOAD_CONST 4 #PRINT_ITEM #PRINT_NEWLINE #LOAD_CONST 0 #RETURN_VALUE age = 5; print age f("Robert", age) #LOAD_NAME 0 #LOAD_CONST 2 #LOAD_NAME 1 #CALL_FUNCTION 2 #POP_TOP print agecall_function --> fast_function
def f(a = 1, b = 2): #LOAD_CONST 0 #LOAD_CONST 1 #LOAD_CONST 2 #MAKE_FUNCTION 2 #STORE_NAME 0 print a + b #LOAD_FAST 0 #LOAD_FAST 1 #BINARY_ADD #PRINT_ITEM #PRINT_NEWLINE #LOAD_CONST 0 #RETURN_VALUE f() #LOAD_NAME 0 #CALL_FUNCTION 0 #POP_TOP f(b=3) #LOAD_NAME 0 #LOAD_CONST 3 #LOAD_CONST 4 #CALL_FUNCTION 256 #POP_TOP #LOAD_CONST 5 #RETURN_VALUE
PyObject * PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, PyObject **args, int argcount, PyObject **kws, int kwcount, PyObject **defs, int defcount, PyObject *closure) { register PyFrameObject *f; register PyObject *retval = NULL; register PyObject **fastlocals, **freevars; PyThreadState *tstate = PyThreadState_GET(); PyObject *x, *u; //[1]:创建PyFrameObject对象 f = PyFrame_New(tstate, co, globals, locals); fastlocals = f->f_localsplus; freevars = f->f_localsplus + co->co_nlocals; //[a]:遍历键参数,确定函数的def语句中是否出现了键参数的名字 for (i = 0; i < kwcount; i++) { PyObject *keyword = kws[2*i]; PyObject *value = kws[2*i + 1]; int j; //[b]:在函数的变量名表中寻找keyword //... for (j = 0; j < co->co_argcount; j++) { PyObject *nm = co_varnames[j]; int cmp = PyObject_RichCompareBool( keyword, nm, Py_EQ); if (cmp > 0) goto kw_found; else if (cmp < 0) goto fail; } if (kwdict == NULL) { PyObject *kwd_str = kwd_as_string(keyword); if (kwd_str) { PyErr_Format(PyExc_TypeError, "%.200s() got an unexpected " "keyword argument '%.400s'", PyString_AsString(co->co_name), PyString_AsString(kwd_str)); Py_DECREF(kwd_str); } goto fail; } PyDict_SetItem(kwdict, keyword, value); continue; kw_found: if (GETLOCAL(j) != NULL) { goto fail; } Py_INCREF(value); SETLOCAL(j, value); } if (co->co_argcount > 0 || co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { int i; int n = argcount; PyObject *kwdict = NULL; //n为CALL_FUNCTION的参数指示的传入的位置参数个数,即na,这里为0 //... //[2]:判断是否使用参数的默认值 if (argcount < co->co_argcount) { //m 一般位置参数的个数 int m = co->co_argcount - defcount; //[3]:函数调用者必须传递一般位置参数的参数值 for (i = argcount; i < m; i++) { if (GETLOCAL(i) == NULL) { goto fail; } } //[4]:n > m意味着调用者希望替换一些默认位置参数的默认值 if (n > m) i = n - m; else i = 0; //[5]:设置默认位置参数的默认值 for (; i < defcount; i++) { if (GETLOCAL(m+i) == NULL) { PyObject *def = defs[i]; Py_INCREF(def); SETLOCAL(m+i, def); } } } } retval = PyEval_EvalFrameEx(f,0); return retval; }
PyObject * PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, PyObject **args, int argcount, PyObject **kws, int kwcount, PyObject **defs, int defcount, PyObject *closure) { register PyFrameObject *f; register PyObject **fastlocals, **freevars; PyThreadState *tstate = PyThreadState_GET(); PyObject *x, *u; //创建PyFrameObject对象 f = PyFrame_New(tstate, co, globals, locals); fastlocals = f->localsplus; freevars = f->f_localsplus + f->f_nlocals; //[1]:判断是否需要处理扩展位置参数或扩展键参数 if(co->co_argcount > 0 || co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)){ int i; int n = argcount; if(argcount > co->co_argcount ){ n = co->co_argcount; } //[2]:设置位置参数的参数值 for(i = 0; i < n; i++){ x = args[i]; SETLOCAL(i, x); } //[3]:处理扩展位置参数 if(co->co_flags & CO_VARARGS){ //[4]:将PyTupleObject对象放入到f_localsplus中 u = PyTuple_New(argcount - n ); SETLOCAL(co->co_argcount, u); //[5]:将扩展位置参数放入到PyTupleObject中 for( i = n; i < argcount; i++){ x = args[i]; PyTuple_SET_ITEM(u, i - n, x); } } } }
PyObject * PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, PyObject **args, int argcount, PyObject **kws, int kwcount, PyObject **defs, int defcount, PyObject *closure) { //... if(co->co_flags > 0 || co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)){ int i; int n = argcount; PyObject *kwdict = NULL; //... //[1]:创建PyDictObject对象,并将其放到f_localsplus中 if(co->co_flags & CO_VARKEYWORDS){ kwdict = PyDict_New(); i = co->co_argcount; //[2]:PyDictObject对象必须在PyTupleObject之后 if(co->co_flags & CO_VARARGS) i++; SETLOCAL(i, kwdict); } //遍历键参数,确定函数的def语句中是否出现了键参数的名字 for(i = 0; i < kwcount; i++){ PyObject *keyword = kws[2 * i]; PyObject *value = kws[2 * i + 1]; int j; //在函数的变量名表中寻找keyword for(j = 0; j < co->co_argcount; j++){ PyObject *nm = PyTuple_GET_ITEM(co->co_varnames, j); int cmp = PyObject_RichCompareBool(keyword, nm, Py_EQ); if(cmp > 0)//在co_varnames中找到keyword break; else if (cmp < 0) goto fail; } //[3]:keyword没有在变量名对象表中出现 if(j >= co->co_argcount){ PyDict_SetItem(kwdict, keyword, value); } //keyword在变量名对象表中出现 else{ SETLOCAL(j, value); } } } }
def get_func(): LOAD_CONST 0 MAKE_FUNCTION STORE_NAME 0 value = "inner" LOAD_CONST 1 STORE_DEREF 0 def inner_func(): LOAD_CLOSUER 0 BUILD_TUPLE LOAD_CONST 2 MAKE_CLOSURE 0 STORE_FAST 0 print value LOAD_DEREF 0 PRINT_ITEM PRINT_NEWLINE LOAD_CONST 0 RETURN_VALUE return inner_func LOAD_FAST 0 RETURN_VALUE show_value = get_func() LOAD_NAME 0 CALL_FUNCTION 0 STORE_NAME 1 show_value() LOAD_NAME 1 CALL_FUNCTION 0 POP_TOP LOAD_CONST RETURN_VALUE
def should_say(fn): def say(*args): print 'say something ...' fn(*args) return say @should_say def func(): print 'in func'
#... def func(): print 'in func' func = should_say(func) func()
《python源码剖析》笔记 python虚拟机中的函数机制,布布扣,bubuko.com
《python源码剖析》笔记 python虚拟机中的函数机制
标签:style class blog code http tar
原文地址:http://blog.csdn.net/zhengsenlie/article/details/33326399