python檔案的編譯
背景知識
- pyc檔案: .pyc 是一種二進位制檔案,是由 .py 檔案經過編譯後,生成一種byte code檔案。 .py 檔案變成 .pyc 檔案後,載入的速度有所提高,而且 .pyc 是一種跨平臺的位元組碼,是由python的虛擬機器來執行的,這個類似於JAVA或者.NET的虛擬機器的概念。 .pyc 的內容是跟python的版本相關的,不同版本編譯後的 .pyc 檔案是不同的,2.5編譯的 .pyc 檔案對於2.4版本的python是無法執行的。
- pyo檔案: .pyo 是優化編譯後的程式 python -O 原始檔 即可將源程式編譯為 .pyo 檔案。
- pyd檔案: .pyd 是python的動態連結庫。
為什麼要編譯Python檔案?
通常Python程式碼是不需要編譯就可以執行的,但Python其實也是有編譯的過程的,與Java和C#一樣Python只能執行位元組碼,Python只是將編譯過程隱藏起來了。將Python檔案編譯為 .pyc 或 .pyo 檔案有兩個目的:
- 由於 .py 檔案是可以直接看到原始碼的,所以如果是開發商業軟體的話就需要將 .py 檔案編譯為看不到原始碼的 .pyc 位元組碼檔案後再發布出去;
- 將 .py 檔案編譯為 .pyc 或 .pyo 檔案可以提高Python程式的載入速度,而且 .pyc 是一種跨平臺的位元組碼,由python的虛擬機器來執行;
python的編譯過程
當我們通過下面的命令來執行一個Python程式時:(Linux中)
-
Python test.py
-
-
-
# test.py中的內容
-
# --------------------------------------------------------
-
#!/usr/bin/env python
-
import mymodule
-
mymodule.say(
"hello")
Python直譯器其實並不一定會讀入 mymodule.py 檔案,它會嘗試讀取 mymodule.pyc 檔案或者 mymodule.pyo 檔案。如果都失敗了,或者 mymodule.py 檔案比 mymodule.pyc/mymodule.pyo 新,才轉而讀入 mymodule.py 檔案。Python只懂得解釋執行位元組碼,所以 mymodule.py 檔案讀入後第一件事就是先進行編譯。編譯的結果會被嘗試儲存到 mymodule.pyc 檔案中。Python的編譯實際上主要是進行文法分析,生成一個抽象語法樹,然後轉儲成位元組碼形式。這一點與Java有些相似,因為它們都生成位元組碼。
編譯Python檔案的方法(Linux)
編譯 .py 檔案有以下幾種方式,所有這些方式都是使用了 py_compile 模組的 compile() 方法。同時我們可以使用 compileall 模組中的 compile_dir() 來編譯某個資料夾下面所有的 .py 檔案,以及可以使用 compile_path 來依次編譯 sys.path 指定路徑下的 .py 檔案。如果看過 compileall 模組的原始碼我們可以知道 compileall 編譯 .py 檔案其實還是呼叫了 py_compile 的 compile() 方法。
在Linux環境下,可以通過寫一個bash指令碼編譯 .py 檔案,也可以直接通過命令列來編譯。(這裡僅介紹通過命令列來編譯的方法):
1. 生成單個的 .pyc or .pyo 檔案
-
# 編譯成pyc檔案
-
# ------------------------------------------------------
-
python -m py_compile $filename
# 其中,$filename是要編譯的python原始碼檔名
-
-
-
# 編譯成pyo檔案
-
# -------------------------------------------------------
-
python -O -m py_compile $filename
-
# 或者
-
1python -OO -m py_compile $filename
-
1
-
1
# 其中, + -O選項表示優化產生的位元組碼,優化程度由PYTHONOPTIMIZE(environment)的值來決定。 + -OO選項表示在-O優化的基礎上移除所有的doc-strings(文件文字)。
2. 批量生成 .pyc 檔案
使用compileall模組可以批量編譯整個目錄下的Python原始碼檔案。
-
# 函式定義
-
compileall.compile_dir(dir, maxlevels=
10, ddir=
None, force=
False, rx=
None, quiet=
False, legacy=
False, optimize=
-1)
-
-
# 用法:
-
python -m compileall $dir
或者可以編寫指令碼來實現:
-
import compileall
-
compileall.compile_dir(
'$dir')
-
-
# 其中,$dir 為Python原始碼所在的目錄。