Python原始碼學習 之bytecode

2021-08-26 04:40:42 字數 3156 閱讀 8646

原始碼

***.py檔案

或 字串

==>

位元組碼

可快取在***.pyc

==>

結果

pythonx.dll

libpythonx.x.a

pythonx.dll

libpythonx.x.a

py_compilestring***(...)

pyeval_eval***(...)

compile

eval

**中通過import使用到的.py檔案會自動編譯成.pyc檔案,如何手動來編譯呢?

>>> import py_compile

>>> py_compile.compile('hello.py')

>>>

python3 -m py_compile hello.py

生成的檔案(個人機子上的結果):

__pycache__/hello.cpython-32.pyc

python -m compileall .

這兒的py_compile和compileall使用的都是builtins模組的compile()函式

在python執行環境中,builtins模組中:

compile()

編譯成位元組碼,code物件(pycodeobject)

eval()、exec()執行

乙個例子:

>>> a = "1+2"

>>> b = compile(a, "test.py", 'single')

>>> type(b)

>>> eval(b)

3

它們對應c高層介面中的下面兩類函式:

py_compilestring***(...)

將python**編譯成bytecode

pyeval_eval***(...)

執行這個bytecode

compile() 和 eval()、exec() 是內建模組中的函式,所以瞅瞅

中定義的方法:

static pymethoddef builtin_methods = ,

//...

, ,

//...

,};

其中:

static pyobject *

builtin_compile(pyobject *self, pyobject *args, pyobject *kwds)

... result = py_compilestringexflags(str, filename, start[mode], &cf, optimize);

goto finally;

finally:

py_decref(filename_obj);

return result;

}

static pyobject *

builtin_eval(pyobject *self, pyobject *args)

cf.cf_flags = pycf_source_is_utf8;

str = source_as_string(cmd, "eval", "string, bytes or code", &cf);

... (void)pyeval_mergecompilerflags(&cf);

result = pyrun_stringflags(str, py_eval_input, globals, locals, &cf);

py_xdecref(tmp);

return result;

}

恩,這樣一來,總算將c**和python**聯絡上了。

前面提到的 bytecode,具體到原始碼中,就是pycodeobject物件了(對應python環境中的code):

先看一下該結構體的定義:

/* bytecode object */

typedef struct pycodeobject;

python提供了簡單的封裝,於是,我們可以直接檢視這些成員。例子:

>>> c = compile("1+2", "test.py", "single")

>>> c.co_argcount

0>>> c.co_code

b'd\x03\x00fd\x02\x00s'

>>> c.co_consts

(1, 2, none, 3)

>>> c.co_name

''>>> c.co_filename

'test.py'

其中 co_code 就是位元組碼了:d\x03\x00fd\x02\x00s

那麼如何理解這些**??

co_code 寫成10進製:10030701002083

100指令碼: load_const

3co_consts中的第3個常數070

指令碼: print_expr

100指令碼: load_const

2co_consts中的第2個常數083

指令碼: return_value

指令碼定義在檔案 include/opcode.h 中。

不過這樣閱讀指令碼真的很難受,幸好,python提供了 dis 模組

用它來看看前面的例子

>>> c = compile("1+2", "test.py", "single")

>>> import dis

>>> dis.dis(c)

1 0 load_const 3 (3)

3 print_expr

4 load_const 2 (none)

7 return_value

恩,一目了然。最開始的那個1是行號,指令碼前面的數字是它在co_code中的索引。

恩,dis 是很有用的東西,不過偶還沒學會怎麼利用它。

Python原始碼學習 之 Python直譯器

include 公有 標頭檔案 lib python編寫的模組 modules c實現的模組 objects 內建物件型別的實現 pc windows下構建python的工程檔案 pcbuild parser 直譯器的 parser tokenizer input handling python 直...

Python原始碼學習 之模組路徑

接前面python原始碼筆記之py initializeex,嘗試看看python中用到的一些path 這部分東西太亂了.具體見pc getpathp.c 和 modules getpath.c 中的注釋 乙個python程式要有執行,必須要能找到 py pyc pyo pyd so 等,如何找到這...

原始碼學習之IntenteService

intentservice是基於service實現的,它會按需求處理一些非同步任務。通過呼叫startservice,客戶端就可以傳送請求了。如果有需要的話,service才會被啟動,在子執行緒依次處理每個intent,處理完任務以後service會停止。使用的時候要繼承intentservice,...