常見的 Python 檔案后綴有:py、pyc 、pyo、 pyi、pyw、 pyd、 pyx 等,
本文只介紹相對常見的一些后綴名,至于一些特別冷門的檔案格式,例如一些文章提到的pyz、pywz、rpy、pyde、pyp、 pyt等,并沒有進行研究,因為這些擴展名資料很少,網上搜到的文章似乎都是同一個出處,只是簡單提了一句,說了等于沒說,
py
最常見的 Python 源代碼檔案,
實際上如果用 python + 檔案 的方式運行代碼,只要檔案內容相同,后綴名是不重要的,也就是說下面的運行結果都是等價的:
python test.py
python test.txt
python test
pyc
常見的 Python 位元組碼快取檔案,
pyc檔案和py檔案一樣,都可以直接執行,下面的運行結果都是等價的:
python test.py
python test.pyc
作用一:提升加載性能
我們知道 Python 代碼在執行時,會先由 Python 決議器翻譯成 PyCodeObject 物件,俗稱位元組碼 (Byte code),然后交給 Python 解釋器來執行位元組碼,
上述程序中翻譯后的位元組碼是保存在記憶體中,程式運行結束就沒了,而代碼沒有修改的情況下,每次生成的位元組碼是一樣的,所以每次跑程式都再走一遍翻譯位元組碼的程序有點浪費性能,因此為了提高加載效率,Python 在程式執行結束后會把每個檔案的位元組碼寫入到硬碟中保存為 xxx.pyc 檔案,這樣下一次再執行這個程式時先在目錄下找有沒有xxx.pyc 檔案,如果有這個對應檔案且修改時間和xxx.py 檔案的修改時間一樣,就不用再執行翻譯成位元組碼的程序,直接讀取xxx.pyc 檔案執行,其實快取pyc 檔案的方式對性能的提升很微小,只有專案檔案非常多的時候才能看到顯著提升,
默認情況下,我們發現并不是所有的py 檔案都會自動生成pyc 檔案,只有被其他檔案 import 過的檔案才會生成對應的pyc 檔案,可能 Python 認為被 import 的檔案重復使用的概率比較高,而主檔案一般只需要加載一次,
簡單做個實驗可以驗證,新建兩個 Python 檔案hello.py和import.py,內容如下:
# hello.py
print("hello")
# import.py
impot hello
直接運行 python hello.py,并沒有生成pyc 檔案,而運行python import.py,在當前目錄下生成了hello.py對應的pyc 檔案,
這里 Python2 和 Python3 有些不同, Python2 是直接在當前目錄下生成同名 pyc 檔案,Python3 是在當前目錄下創建了__pycache__檔案夾,然后在檔案夾內創建了一個包含 Python 版本資訊的xxx.cpython-37.pyc 檔案,
Python2

Python3

作用二:隱藏源代碼
pyc格式是給解釋器看的二進制檔案,直接用編輯器打開看上去是亂碼,所以將 Python 代碼先編譯成pyc檔案再交付給別人使用,一定程度上實作隱藏源代碼的效果,
默認情況下,主檔案不會生成pyc檔案,可以通過 Python 自帶的py_compile或compileall 庫,手動將所有py檔案"編譯"成pyc檔案,
python -m py_compile *.py
python -m compileall *.py
Python2

Python3

反編譯 pyc
前面說了,是“一定程度上實作隱藏源代碼的效果”,其實可以通過反編譯pyc檔案來獲得py原始碼,而且反編譯的難度并不大,
uncompyle6是一個專門用于將pyc反編譯為py原始碼的第三方庫,安裝方式:
pip install uncompyle6
執行下面命令可以將剛才生成的pyc反編譯為py檔案:
uncompyle6 -o . *.pyc

打開生成的檔案hello.cpython-37.py和import.cpython-37.py,可以看到和之前的py代碼內容一模一樣,不過多了一些 Python 的版本資訊,

魔高一尺,道高一丈,有反編譯技術就有防止反編譯技術,更多了解參見這篇文章:通過位元組碼混淆來保護Python代碼,
pyo
優化后的 Python 位元組碼快取檔案,
pyo檔案的作用和pyc檔案沒啥區別,唯一的優化就是去掉了斷言陳述句,即assert陳述句,官方檔案描述:
When the Python interpreter is invoked with the -O flag, optimized code is generated and stored in .pyo files. The optimizer currently doesn’t help much; it only removes assert statements. When -O is used, all bytecode is optimized; .pyc files are ignored and .py files are compiled to optimized bytecode.
同樣可以利用py_compile或compileall 庫將上面示例的兩個檔案編譯成pyo檔案,只是多加一個引數-O,運行結果也沒有任何變化:
python -O -m py_compile *.py
python -O -m compileall *.py

從 Python3.5 開始,Python 只使用 pyc 而不再使用pyo,所以下面命令也無法生成 pyo檔案,生成的依然是 pyc 檔案:
python3 -O -m py_compile *.py
python3 -O -m compileall *.py

pyi
Python 的存根檔案,用于代碼檢查時的型別提示,
pyi檔案是PEP484提案規定的一種用于 Python 代碼型別提示(Type Hints)的檔案,PEP即Python Enhancement Proposals,是經過 Python 社區核心開發者討論并一致同意后,對外發布的一些正式規范檔案,例如我們常說的Python之禪(PEP20),代碼風格 PEP8 格式化(PEP8),將 print 改為函式(PEP3105)等,關于PEP的更多了解見這篇文章:學習Python,怎能不懂點PEP呢?,
常用的 IDE 都會有型別檢查提示功能,比如在 PyCharm 中,當我們給一個函式傳入一個錯誤的型別時會給出對應的提示,這其實不是 IDE 的特殊開發的功能,它只是集成了PEP484的規定,利用了已經預先生成好的 pyi檔案,
舉個例子,os.makedirs是標準庫中用于創建檔案夾路徑的函式,它的入參應該是一個字串型別,如果傳入一個 int 型別,IDE 會立刻給出提示,

按住ctrl點進去,進入到 os 模塊定義os.makedirs的地方,發現前面有個*號,滑鼠放上去會提示Has stub item in __init__.pyi,

點擊*號就會跳到對應的__init__.pyi檔案,這個檔案里按照PEP484規定,為os模塊每個函式都定義了對應的型別檢查規則,

關于pyi檔案的定義規則以及自己如何生成,詳見官方檔案:PEP 484 – Type Hints
pyw
一種 Python 源代碼檔案,一般只存在于 Windows 系統,
pyw檔案和py檔案除了后綴名不一樣之外沒有任何區別,兩者都是 Python 原始碼檔案,前面 py那一節說過“如果用 python + 檔案 的方式運行代碼,只要檔案內容相同,后綴名是不重要的”,這一點在 Windows 系統和 Linux 系統都是一樣的,
Windows 系統,新建兩個內容相同的 Python 檔案hello.py和hello.pyw,用python + 檔案 的方式運行,結果一樣:
# hello.py
print("hello")
# hello.pyw
print("hello")

那為什么還要有pyw檔案呢?
在Windows 系統上雙擊檔案時,系統會根據檔案擴展名來呼叫關聯的exe程式來運行這個檔案,打開 Python 安裝目錄,可以看到有python.exe和pythonw.exe兩個exe,其中python.exe關聯了py檔案,pythonw.exe關聯了pyw檔案,跟 python.exe 相比,pythonw.exe運行時不會彈出控制臺視窗, stdout 、stderr 和 stdin 都無效,所以像 print 這種把內容輸出到 stdout 的操作就不會有列印結果(cmd 視窗都沒有了也沒有地方顯示了),

所以在用 Python 開發 GUI 程式時,如果不想讓程式運行的時候彈出一個黑乎乎的 cmd 框,就可以將原始碼檔案后綴名改為pyw格式,但是我感覺這個pww格式用處并不大,實際使用很少有人雙擊py或者pyw檔案來運行 Python 代碼,我之前曾用tkinter開發過帶 Windows 界面的 Python 程式,當時是通過雙擊 bat腳本啟動 Python 腳本同時關閉 cmd 界面框,來避免彈出黑框框的,
pyd
Python 可直接呼叫的 C 語言元件檔案,一般只存在于 Windows 系統,
Python 是一種膠水語言,我們可以將對速度要求比較高的那一部分代碼使用 C 語言撰寫,編譯成元件檔案,再通過 Python 來呼叫,一般來說,在 Linux 上是 so檔案,在 Windows 系統上是DLL檔案,
例如有一個 C 語言撰寫的 Windows 元件 test_lib.dll,編譯前的代碼如下:
int sum(int x, int y)
{
return x + y;
}
我們可以在 Python 代碼中通過下面的方式來呼叫
# test_lib.dll 放在當前目錄下
import ctypes
from ctypes import *
test_lib = ctypes.windll.LoadLibrary("test_lib.dll")
a = ctypes.c_int(1)
b = ctypes.c_int(2)
out = test_lib.sum(a, b)
print(out) # 3
在 Windows 系統上,Python 還有一種 pyd格式的元件,上面的呼叫方式是先通過ctypes.windll.LoadLibrary 方法將元件加載進來,而pyd格式就可以在 Python 代碼中直接import進來,類似下面這樣:
# test_lib.pyd 放在當前目錄下
import test_lib
out = test_lib.sum(1, 2)
print(out) # 3
關于 pyd檔案和dll檔案的區別,可參考官方檔案的說明:
Is a
*.pydfile the same as a DLL?Yes, .pyd files are dll’s, but there are a few differences. If you have a DLL named
foo.pyd, then it must have a functionPyInit_foo(). You can then write Python “import foo”, and Python will search for foo.pyd (as well as foo.py, foo.pyc) and if it finds it, will attempt to callPyInit_foo()to initialize it. You do not link your .exe with foo.lib, as that would cause Windows to require the DLL to be present.Note that the search path for foo.pyd is PYTHONPATH, not the same as the path that Windows uses to search for foo.dll. Also, foo.pyd need not be present to run your program, whereas if you linked your program with a dll, the dll is required. Of course, foo.pyd is required if you want to say
import foo. In a DLL, linkage is declared in the source code with__declspec(dllexport). In a .pyd, linkage is defined in a list of available functions.
C 語言代碼和 Python 代碼都可以通過一定的方法編譯成pyd格式的檔案,本人并沒有實際使用過pyd檔案,詳細方法可參考下面的文章:
使用C++創建Pyd檔案擴展Python模塊
Python源代碼保護(Python檔案編譯生成pyd/so庫檔案)
pyx
Cython 源代碼檔案,
注意是 Cython 不是 CPython,Cython 可以說是一種編程語言, 它結合了Python 的語法和有 C/C++的效率,用 Cython 寫完的代碼可以很容易轉成 C 語言代碼,然后又可以再編譯成元件(pyd或dll)供 Python 呼叫,所以 Cython 一般用來撰寫 Python 的 C 擴展,上面說的 Python 檔案編譯生成 pyd 檔案就是利用 Cython 來實作的 ,Cython 的源代碼檔案一般為pyx后綴,
總結
| 后綴名 | 作用 |
|---|---|
| py | 最常見的 Python 源代碼檔案, |
| pyc | 常見的 Python 位元組碼快取檔案,可以反編譯成 py 檔案, |
| pyo | 另一種 Python 位元組碼快取檔案,只存在于 Python2 及 Python3.5 之前的版本, |
| pyi | Python 的存根檔案,常用于 IDE 代碼格式檢查時的型別提示, |
| pyw | 另一種 Python 源代碼檔案,一般只存在于 Windows 系統, |
| pyd | 一種 Python 可直接呼叫的 C 語言元件檔案,一般只存在于 Windows 系統, |
| pyx | Cython 源代碼檔案,一般用來撰寫 Python 的 C 擴展, |
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/282628.html
標籤:python
