函數(shù)毡熏,是一個(gè)動(dòng)態(tài)的過程舍扰,在函數(shù)被調(diào)用時(shí)倦蚪,系統(tǒng)會(huì)動(dòng)態(tài)創(chuàng)建一個(gè)棧幀,函數(shù)對應(yīng)的表示結(jié)構(gòu):
typedef struct {
PyObject_HEAD
PyObject *func_code; /* A code object */
PyObject *func_globals; /* 函數(shù)運(yùn)行時(shí)的global名稱空間 */
PyObject *func_defaults; /* 函數(shù)默認(rèn)參數(shù) NULL or a tuple */
PyObject *func_closure; // 用于實(shí)現(xiàn)閉包的
PyObject *func_doc; /* The __doc__ attribute, can be anything */
PyObject *func_name; /* The __name__ attribute, a string object */
PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */
PyObject *func_weakreflist; /* List of weak references */
PyObject *func_module; /* The __module__ attribute, can be anything */
} PyFunctionObject;
函數(shù)內(nèi)包含的func_code則對應(yīng)的是函數(shù)的代碼边苹,靜態(tài)的陵且、在編譯時(shí)就定義好了,而函數(shù)則是在運(yùn)行時(shí)个束,即運(yùn)行到def語句時(shí)構(gòu)建(func_globals是在這時(shí)候才能確定的)
所以慕购,一段代碼肯定對應(yīng)一個(gè)code object,但是函數(shù)對象可能有多個(gè)茬底,例如多次調(diào)用該函數(shù)沪悲,會(huì)構(gòu)建多個(gè)func object,這些func object的func_code都指向一個(gè)code object桩警。
函數(shù)對象的創(chuàng)建
注意可训,Python在執(zhí)行到def語句后昌妹,接著執(zhí)行其后的代碼捶枢,而不是進(jìn)入到函數(shù)體內(nèi)執(zhí)行其中的語句(這些語句是在編譯時(shí)就已經(jīng)構(gòu)建好了對應(yīng)的code object),函數(shù)的聲明和實(shí)現(xiàn)時(shí)分離的飞崖,分在了不同的code object中烂叔。
def語句
對應(yīng)的機(jī)器碼有三條:
load_const 0
裝載編譯好的函數(shù)體的code object
make_function
構(gòu)建函數(shù)對象
store_name 0
把構(gòu)建好的函數(shù)對象添加到名稱空間內(nèi)
make_function
pop
把之前裝載的函數(shù)體的code object取出來
PyFunction_New(v, f->f_globals)
主要是分配函數(shù)對象的空間,給函數(shù)對象中的func_code, func_globals等賦值固歪。
push
把創(chuàng)建好的函數(shù)對象壓入運(yùn)行時(shí)棧中蒜鸡,最后通過store_name添加。
函數(shù)調(diào)用
f()
對應(yīng)的機(jī)器碼五條:
load_name 0
獲取該函數(shù)對象
call_function 0
調(diào)用
pop_top
load_const
return_value
返回值