本文为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 age
call_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()