原始碼:
***.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,...