1. 過程概述
Python先把代碼(.py文件)編譯成字節碼,交給字節碼虛擬機,然后虛擬機一條一條執行字節碼指令,從而完成程序的執行。
2. 字節碼
字節碼在Python虛擬機程序里對應的是PyCodeObject對象。
.pyc文件是字節碼在磁盤上的表現形式。
3. pyc文件
PyCodeObject對象的創建時機是模塊加載的時候,即import。
Python test.py會對test.py進行編譯成字節碼并解釋執行,但是不會生成test.pyc。
如果test.py加載了其他模塊,如import util,Python會對util.py進行編譯成字節碼,生成util.pyc,然后對字節碼解釋執行。
如果想生成test.pyc,我們可以使用Python內置模塊py_compile來編譯。
加載模塊時,如果同時存在.py和.pyc,Python會嘗試使用.pyc,如果.pyc的編譯時間早于.py的修改時間,則重新編譯.py并更新.pyc。
4. PyCodeObject
Python代碼的編譯結果就是PyCodeObject對象。
typedef struct { PyObject_HEAD int co_argcount; /* 位置參數個數 */ int co_nlocals; /* 局部變量個數 */ int co_stacksize; /* 棧大小 */ int co_flags; PyObject *co_code; /* 字節碼指令序列 */ PyObject *co_consts; /* 所有常量集合 */ PyObject *co_names; /* 所有符號名稱集合 */ PyObject *co_varnames; /* 局部變量名稱集合 */ PyObject *co_freevars; /* 閉包用的的變量名集合 */ PyObject *co_cellvars; /* 內部嵌套函數引用的變量名集合 */ /* The rest doesn't count for hash/cmp */ PyObject *co_filename; /* 代碼所在文件名 */ PyObject *co_name; /* 模塊名|函數名|類名 */ int co_firstlineno; /* 代碼塊在文件中的起始行號 */ PyObject *co_lnotab; /* 字節碼指令和行號的對應關系 */ void *co_zombieframe; /* for optimization only (see frameobject.c) */} PyCodeObject; typedef struct { PyObject_HEAD int co_argcount; /* 位置參數個數 */ int co_nlocals; /* 局部變量個數 */ int co_stacksize; /* 棧大小 */ int co_flags; PyObject *co_code; /* 字節碼指令序列 */ PyObject *co_consts; /* 所有常量集合 */ PyObject *co_names; /* 所有符號名稱集合 */ PyObject *co_varnames; /* 局部變量名稱集合 */ PyObject *co_freevars; /* 閉包用的的變量名集合 */ PyObject *co_cellvars; /* 內部嵌套函數引用的變量名集合 */ /* The rest doesn't count for hash/cmp */ PyObject *co_filename; /* 代碼所在文件名 */ PyObject *co_name; /* 模塊名|函數名|類名 */ int co_firstlineno; /* 代碼塊在文件中的起始行號 */ PyObject *co_lnotab; /* 字節碼指令和行號的對應關系 */ void *co_zombieframe; /* for optimization only (see frameobject.c) */} PyCodeObject;
5. pyc文件格式
加載模塊時,模塊對應的PyCodeObject對象被寫入.pyc文件,格式如下:
新聞熱點
疑難解答