reference: Python 源码剖析
Python_vm_function
PyFunctionObject对象
无参函数调用
函数执行时的名字空间
函数参数的实现
函数中局部变量的访问
嵌套函数、闭包与decorator
1.Python 虚拟机中的函数机制 a.PyFunctionObject对象 1 2 3 4 5 6 7 8 9 10 11 12 13 [funcobject.h] typedef struct { PyObject_HEAD PyObject* func_code; PyObject* func_globals; PyObject* func_defaults; PyObject* func_closure; PyObject* func_doc; PyObject* func_name; PyObject* func_dict; PyObject* func_weakreflist; PyObject* func_module; } PyFunctionObject;
b.无参函数调用
1 2 3 4 5 //func_0.py def f () : print "Function" f()
1 2 3 4 5 6 7 [MAKE_FUNCTION] v = POP(); x = PyFunction_New(v,f->f_globals); Py_DECREF(v); ... PUSH(x); break ;
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 [function.c] PyObject* PyFunction_New (PyObject* code,PyObject* globals) { PyFunctionObject* op = PyObject_GC_New(PyFunctionObject,&PyFunction_Type); static PyObject* __name__ = 0 ; if (op != NULL ){ ... op->func_code = code; op->func_globals = globals; op->func_name = ((PyCodeObject *)code)->co_name; consts = ((PyCodeObject *)code)->co_consts; if (PyTuple_Size(consts) >= 1 ){ doc = PyTuple_GetItem(consts,0 ); if (!PyString_Check(doc) && !PyUnicode_Check(doc)) doc = PyNone; } else doc = PyNone; ..... }else { return NULL ; } return (PyObject *)op; }
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 [CALL_FUNCTION] PyObject** sp; sp = stack_pointer; x = call_function(&sp,oparg); stack_pointer = sp; PUSH(x); if (x != NULL ) continue ; break ;[ceval.c] static PyObject* call_function (PyObject** pp_stack,int oparg) { int na = oparg & 0xff ; int nk = (oparg>>8 ) & 0xff ; int n = na + 2 *nk; 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 ){ ... } if (PyFunction_Check(func)) x = fast_function(func,pp_stack,n,na,nk); else x = do_call(func,pp_stack,na,nk); .... } .... 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 [ceval.c] 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 ; 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 = ((PyTupleObject *)argdefs)->ob_size; } return PyEval_EvalCodeEx(co,globals,(PyObject *)NULL ,(**pp_stack) - n, na, (*pp_stack) - 2 *nk, nk ,d , nd, PyFunction_GET_CLOSURE(func)); }
c.函数执行时的名字空间
d.函数参数的实现
参数类别
位置参数(positional argument): f(a,b)、a和b被称为位置参数
键参数(key argument) : f(a,b,name=’Python’),其中的name=’Python’被称为键参数
扩展位置参数(excess positional argument) : def f(a,b,list),其中的 list被称为扩展位置参数
扩展键参数(excess key argument) : def (a,b,keys),其中的 key被称为扩展键参数
CALL_FUNCTION指令参数的长度为两个字节 ,在低字节 ,记录位置参数 的个数,在高字节 ,记录键参数 的个数,所以理论上可以有256个位置参数和256个键参数
1 2 3 4 5 6 7 8 9 10 11 //func_1 def f (name,age) : age += 5 print "[" , name, ", " , age, "]" age = 5 print agef("Robert" ,age) print age
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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); if (argdefs == NULL && co->co_argcount == n && nk = 0 && co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)){ PyFrameObject* f; PyThreadState* tstate = PyThreadState_GET(); PyObject** fastlocals, **stack ; int i; f = PyFrame_New(tstate,co,globals,NULL ); fastlocals = f->f_localsplus; stack = (*pp_stack) - n; for (i = 0 ; i < n; ++i){ fastlocals[i] = *stack ++; } retval = PyEval_EvalFrameEx(f,0 ); .... } .... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [frameobject.c] PyFrameObject* PyFrame_New (PyThreadState* tstate, PyCodeObject* code, PyObject* globals, PyObject* locals) { PyFrameObject* f; int extras,ncells,nfrees,i; ncells = PyTuple_GET_SIZE(code->co_cellvars); nfrees = PyTuple_GET_SIZE(code->co_freevars); extras = code->co_stacksize + code->co_nlocals + ncells + nfrees; .... f = PyObject_GC_NewVar(PyFrameObject,*PyFrame_Type,extras); ... extras = f->f_nlocals + ncells + nfrees; for ( i = 0 ; i < extras; i++){ f->f_localsplus[i] = NULL ; } f->f_valuestack = f->f_localsplus + extras; f->f_stacktop = f->f_valuestack; return f; } `
结论:函数的参数存放在运行时栈之前的那片内存中
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 [ceval.c] PyObject* PyEval_EvalFrameEx (PyFrameObject* f, int throwflag) { register PyObject** fastlocals; .... fastlocals = f->f_localsplus; .... } #define GETLOCAL(i) (fastlocals[i]) [LOAD_FAST] x = GETLOCAL(oparg); if (x != NULL ){ Py_INCREF(x); PUSH(x); goto fast_next_opcode; } #define SETLOCAL(i,value) do { PyObject* tmp = GETLOCAL(i); GETLOCAL(i) = value; Py_XDECREF(tmp); }while (0 ) [STORE_FAST] v = POP(); SETLOCAL(oparg,v); goto fast_next_opcode;
1 2 3 4 5 def f (a=1 ,b=2 ) : print a + b f() f(b=3 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [MAKE_FUNCTION] v = POP(); x = PyFunction_New(v,f->f_globals); Py_DECREF(v); if (x != NULL && oparg > 0 ){ v = PyTuple_New(oparg); while (--oparg >= 0 ){ w = POP(); PyTuple_SET_ITEM(v,oparg,w); } err = PyFunction_SetDefaults(x,v); Py_DECREF(v); } PUSH(x); [funcobject.c] int PyFunction_SetDefaults (PyObject* op, PyObject* defaults) { ((PyFunctionObject *)op)->func_defaults = defaults; return 0 ; }
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 [ceval.c] 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 ; 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 = ((PyTupleObject *)argdefs)->ob_size; } return PyEval_EvalCodeEx(co,globals,(PyObject *)NULL , (**pp_stack) - n, na, (*pp_stack) - 2 *nk, nk, d, nd, PyFunction_GET_CLOSURE(func)); }
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 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; f = PyFrame_New(tstate,co,globals,locals); fastlocals = f->f_localsplus; freevars = f->f_localsplus + f->f_nlocals; if (co->co_argcount > 0 || co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)){ int i; int n = argcount; .... if (argcount < co->co_argcount){ int m = co->co_argcount - defcount; for (i = argcount; i < m; i++){ if (GETLOCAL(i) == NULL ){ goto fail; } } if (n > m) i = n - m else i = 0 ; 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; }
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 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_argcount > 0 || co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)){ int i; int n = argcount; ... for (i = 0 ; i < kwcount; i++){ PyObject* keyword = kws[2 *i]; PyObject* value = kws[2 *i + 1 ]; int j; 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 ) break ; else if (cmp < 0 ) goto fail; } if ( j >= co->co_argcount){ ... } else { if (GETLOCAL(j) != NULL ){ goto fail; } Py_INCREF(value); SETLOCAL(j,value); } } ..... for (; i < defcount; i++){ if (GETLOCAL(m+i) == NULL ){ PyObject* def = defs[i]; Py_INCREF(def); SETLOCAL(m+i,def); } } } }
*list是由PyTupleObject实现,**key是由PyDictObject实现
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 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; f = PyFrame_New(tstate,co,globals,locals); fastlocals = f->f_localsplus; freevars = f->f_localsplus + f->f_nlocals; 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; } for (i = 0 ; i < n; i++){ x = args[i]; SETLOCAL(i,x); } if (co->co_flags & CO_VARARGS){ u = PyTuple_New(argcount - n); SETLOCAL(co->co_argcount,u); for ( i = n; i < argcount; i++){ x = args[i]; PyTuple_SET_ITEM(u,i-n,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 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_argcount > 0 || co->co_flags * (CO_VARARGS | CO_VARKEYWORDS)){ int i; int n = argcount; PyObject* kwdict = NULL ; ... if (co->co_flags && CO_VARKEYWORDS){ kwdict = PyDict_New(); i = co->co_argcount; if (co->co_flags && CO_VARARGS) i++; SETLOCAL(i,kwdict); } for (i = 0l i < kwcount; i++){ PyObject* keyword = kws[2 *i]; PyObject* value = kws[2 *i + 1 ]; int j; 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 ) break else if (cmp < 0 ) goto fail; } if (j >= co->co_argcount){ PyDict_SetItem(kwdict,keyword,value); } else { SETLOCAL(j,value); } } } }
e.函数中局部变量的访问 1 2 3 4 5 6 7 8 9 10 11 12 [frameobject.c] PyFrameObject* PyFrame_New (PyThreadState* tstate, PyCodeObject* code, PyObject* globals, PyObject* locals) { .... if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) == (CO_NEWLOCALS | CO_OPTIMIZED)) locals = NULL ; ... f->f_locals = locals; ... }
局部变量也在f_localsplus运行时栈前面的那段内存,不使用local名字空间是因为用静态方法来实现
f.嵌套函数、闭包与decorator 1 2 3 4 5 6 [compare.py] def compare (base,value) : return value > base compare(10 ,5 ) compare(10 ,20 )
1 2 3 4 5 6 7 8 9 10 [compare2.py] base = 1 def get_compare (base) : def real_compare (value) : return value > base return real_compare compare_with_10 = get_compare(10 ) print compare_with_10(5 )print compare_with_10(20 )
1 2 3 4 5 6 7 8 9 10 11 [compare3.py] base = 1 def get_compare (base) : def real_compare (value,base = base) : return value > base return real_compare compare_with_10 = get_compare(10 ) print compare_with_10(5 )print compare_with_10(20 )print compare_with_10(5 ,1 )
在PyCodeObject中,与嵌套函数相关的属性是co_cellvars和co_freevars
co_cellvars:通常是一个tuple,保存嵌套的作用域中使用的变量名集合
co_freevars:通常是一个tuple,保存使用了的外层作用域中的变量名集合
1 2 3 4 5 6 7 8 9 [closure.py] def get_func () : value = "inner" def inner_func () : print value return inner_func show_value = get_func() show_value()
在PyFrameObject对象中,与闭包相关的属性是f_localsplus
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 [ceval.c] PyObject* PyEval_EvalCodeEx (...) { ... if (PyTuple_GET_SIZE(co->co_cellvars)){ int i,j,nargs,found; char * cellname, *argname; PyObject* c; .... for ( i = 0 ; i < PyTuple_GET_SIZE(co->co_cellvars); ++i){ cellname = PyString_AS_STRING(PyTuple_GET_ITEM(co->co_cellvars,i)); found = 0 ; ... if (found == 0 ){ c = PyCell_New(NULL ); if (c == NULL ){ goto fail; } SETLOCAL(co->co_nlocals + i, c); } } } } [cellobject.h] typedef struct { PyObject_HEAD PyObject* ob_ref; } PyCellObject; [cellobject.c] PyObject* PyCell_New (PyObject* obj) { PyCellObject* op; op = (PyCellObject *)PyObject_GC_New(PyCellObject,&PyCell_Type); op->ob_ref = obj; Py_XINCREF(obj); _PyObject_GC_TRACK(op); return (PyObject *)op; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [PyEval_EvalFrameEx] freevars = f->f_localsplus + co->co_nlocals [STORE_DEREF] w = POP() x = freevars[oparg]; PyCell_Set(x,w); Py_DECREF(w); [cellobject.h] #define PyCell_SET(op,v) (((PyCellObject *)(op))->ob_ref = v) [cellobject.c] int PyCell_SET (PyObject* op, PyObject* obj) { Py_XDECREF(((PyCellObject *)op)->ob_ref); Py_XINCREF(obj); PyCell_SET(op,obj); return 0 ; }
1 2 3 4 5 [LOAD_CLOSURE] x = freevars[oparg]; Py_INCREF(x); PUSH(x);
1 2 3 4 5 6 7 8 9 10 [MAKE_CLOSURE] { v = POP(); x = PyFunction_New(v,f->f_globals); v = POP(); err = PyFuntion_SetClosure(x,v); 绑定约束集合 .../处理拥有默认值的参数 PUSH(x); }
closure实在get_func中被创建的,在inner_func中被使用的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 \\CALL_FUNCTION中,inner_func对应的PyCodeObject中的co_flags里包含了CO_NESTED,不能通过快速通道 [ceval.c] PyObject* PyEval_EvalCodeEx (...) { ... if (PyTuple_GET_SIZE(co->co_freevars)){ int i; for (i = 0 ; i < PyTuple_GET_SIZE(co->co_freevars); ++i){ PyObject* o = PyTuple_GET_ITEM(closure,i); freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o; } } } [funcobject.h] #define PyFunction_GET_CLOSURE(func) (((PyFunctionObject *)func)->func_closure) [ceval.c] PyObject* fast_function (...) { ... return PyEval_EvalCodeEx(...,PyFunction_GET_CLOSURE(func)); }
1 2 3 4 5 6 7 8 [LOAD_DEREF] x = freevars[oparg]; w = PyCell_Get(x); if ( w != NULL ){ PUSH(w); continue ; } ....
基于closure技术上,实现了decorator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [decorator.py] def should_say (fn) : def say (*args) : print 'say something...' fn(*args) return say @should_say def func () : print 'in func' //输出结果为 //say something // in func func() // 相当于 func = should_say(func)