Python學習系列之pyc文件

一、什麼是pyc文件

pyc是一種二進制文件,是由py文件經過編譯後,生成的文件,是一種byte code字節碼,py文件變成pyc文件後,加載的速度有所提高,而且pyc是一種跨平臺的字節碼,是由Python的虛擬機來執行的,這個是類似於Java或者.NET的虛擬機的概念,從而實現跨平臺。pyc文件經過python解釋器最終會生成機器碼運行。所以pyc文件是可以跨平臺部署的,類似Java的.class文件。如果py文件改變,也會重新生成pyc文件。

pyc的內容,是跟python的版本相關的,不同版本編譯後的pyc文件是不同的,2.5編譯的pyc文件,2.4版本的python是無法執行的。

Python是完全面向對象的語言,Python文件在經過解釋器解釋後生成字節碼對象PyCodeObject,pyc文件可以理解爲是PyCodeObject對象的持久化保存方式。pyo是優化的字節碼文件。當python程序運行時,編譯的結果是保存在位於內存中的PyCodeObject中,當Python程序運行結束時,Python解釋器則將PyCodeObject寫回到pyc文件中。當python程序第二次運行時,首先程序會在硬盤中尋找pyc文件,如果找到,則直接載入,否則就重複上面的過程。所以,我們可以說pyc文件其實是PyCodeObject的一種持久化保存方式。

Python選項中:

  • -O,表示優化生成.pyo字節碼。
  • -OO,表示進一步移除-O選項生成的字節碼文件中的文檔字符串(這是在作用效果上解釋的,而不是說從-O選項得到的文件去除)。
  • -m,表示導入並運行指定的模塊,也就是生成pyc文件。

其他文件:

  • pyo是優化編譯後的程序 python -O 源文件即可將源程序編譯爲pyo文件。相比於.pyc文件更小,也可以提高加載速度。但對於嵌入式系統,它可將所需模塊編譯成.pyo文件以減少容量
  • pyd是python的動態鏈接庫。

1.1 爲什麼需要pyc文件

(1)python爲了提高運行效率也會進行編譯

python是解釋型語言,運行的時候需要通過python解釋器解釋執行。我們知道解釋型語言最大的問題是運行速度比編譯性慢,因爲編譯性語言會產生二進制執行文件,也就是不跨平臺的機器指令。所以如果先編譯出pyc文件後,可以節省編譯這一步的耗時時間。在一定程度上提高程序的運行速度。

我們一般認爲C/C++是編譯語言,ruby是解釋型語言。而Java是先編譯後解釋的語言:Java首先是通過編譯器編譯成字節碼文件,然後在運行時通過解釋器給解釋成機器文件。Java,.net,python等基於虛擬機的語言,我們又不能把語言純粹地分成解釋型和編譯型這兩種。Python也是一門基於虛擬機的語言。當我們在命令行中輸入python hello.py時,其實是激活了Python的“解釋器”,告訴“解釋器”:你要開始工作了。可是在“解釋”之前,其實執行的第一項工作和Java一樣,是編譯。

一般的IDE,比如Eclipse都會將這兩步合併爲一步。先編譯後解釋:

Python解釋器將源碼轉換爲字節碼(跨平臺,統一的,只不過不同OS的虛擬機基於它產生不同的機器指令實現跨平臺),然後再由解釋器來執行這些字節碼,轉化爲合適的機器指令,然後執行。

(2)防止源碼泄露。

因爲py文件是可以直接看到源碼的,如果你是開發商業軟件的話,不可能把源碼也泄漏出去吧?所以就需要編譯爲pyc後,再發布出去。當然,pyc文件也是可以反編譯的,不同版本編譯後的pyc文件是不同的,根據python源碼中提供的opcode,可以根據pyc文件反編譯出py文件源碼,網上可以找到一個反編譯python2.3版本的pyc文件的工具,不過該工具從python2.4開始就要收費了,如果需要反編譯出新版本的pyc文件的話,就需要自己動手了,不過你可以自己修改python的源代碼中的opcode文件,重新編譯python,從而防止不法分子的破解。

1.2 一定產生pyc嗎?

實際開發中我們發現有的py文件產生pyc,而有的py文件不產生pyc。

pyc文件只有在文件被當成模塊導入時纔會生成。也就是說,Python解釋器認爲,只有import進行的模塊才需要被重用。 生成pyc文件的好處顯而易見,當我們多次運行程序時,不需要重新對該模塊進行重新的解釋。主文件一般只需要加載一次不會被其他模塊導入,所以一般主文件不會生成pyc文件。

當有別的程序再次import這些模塊時,python就不用再重新解析py文件,而是讀入pyc文件就可以了。

1.3 如何產生pyc文件?

因爲並不是一定會產生pyc文件,所以在什麼情況下產生pyc文件?如何產生?

(1)被當做模塊調用的時候會自動生成pyc文件

  一般是python腳本被當做模塊,被其他腳本文件調用時,就會產生pyc文件,舉個例子:

  如果你寫了一個腳本文件image.py是用來生成驗證碼的,如果你在index.py文件中想引用這個腳本的功能,就需要通過import導入image.py文件,然後,如果你運行index.py文件,那就會在image.py文件所在的路徑生成一個image.pyc文件。

(2)對於py文件,可以執行下面命令來生成pyc文件。參數-m。

python中.pyc文件是什麼?

(3)通過代碼來生成pyc文件。

生成單個pyc文件

Python提供了內置的類庫來實現把py文件編譯爲pyc文件,這個模塊就是 py_compile 模塊。

python中.pyc文件是什麼?

compile函數原型:

compile(file[, cfile[, dfile[, doraise]]])
  • file 表示需要編譯的py文件的路徑
  • cfile 表示編譯後的pyc文件名稱和路徑,默認爲直接在file文件名後加c 或者 o,o表示優化的字節碼
  • dfile it is used as the name of the source file in error messages instead of file
  • doraise 可以是兩個值,True或者False,如果爲True,則會引發一個PyCompileError,否則如果編譯文件出錯,則會有一個錯誤,默認顯示在sys.stderr中,而不會引發異常

批量生成pyc文件

一般來說,我們的工程都是在一個目錄下的,一般不會說僅僅編譯一個py文件而已,而是需要把整個文件夾下的py文件都編譯爲pyc文件,python又爲了我們提供了另一個模塊:compileall 。使用方法如下:

import compileall

compileall.compile_dir(r'H:/game')

這樣就把game目錄,以及其子目錄下的py文件編譯爲pyc文件了。來看下compile_dir函數的說明:

compile_dir(dir[, maxlevels[, ddir[, force[, rx[, quiet]]]]])
  • dir 表示需要編譯的文件夾位置
  • maxlevels 表示需要遞歸編譯的子目錄的層數,默認是10層,即默認會把10層子目錄中的py文件編譯爲pyc
  • ddir it is used as the base path from which the filenames used in error messages will be generated。
  • force 如果爲True,則會強制編譯爲pyc,即使現在的pyc文件是最新的,還會強制編譯一次,pyc文件中包含有時間戳,python編譯器會根據時間來決定,是否需要重新生成一次pyc文件
  • rx 表示一個正則表達式,比如可以排除掉不想要的目錄,或者只有符合條件的目錄才進行編譯
  • quiet 如果爲True,則編譯後,不會在標準輸出中,打印出信息

1.4 pyc文件的過期時間

  • 在生成pyc文件的同時,寫入了一個Long型的變量,用於記錄最近修改的時間;
  • 每次載入之前都先檢查一下py文件和pyc文件的最後修改日期,如果不一致則會生成一個新的pyc文件

1.5 pyc文件的組成

pyc文件一般由3個部分組成:

  • 最開始4個字節是一個Maigc int,標識此pyc的版本信息,不同的版本的 Magic 都在 Python/import.c 內定義
  • 接下來四個字節還是個int,是pyc產生的時間(1970.01.01到產生pyc時候的秒數)
  • 接下來是個序列化了的 PyCodeObject(此結構在 Include/code.h 內定義),序列化方法在 Python/marshal.c 內定義

1.6 導入和模塊

模塊其實也是一個python文件。我們把一些功能相關的代碼寫到一個模塊裏。這樣,當你需要用到某個功能時,就將這個模塊導入,就可以直接使用它的函數了,非常的方便。

在python中,一個模塊就是一個py文件,可以說一個文件就是一個獨立的模塊,一個獨立的模塊就是一個py文件。你自己寫的py文件,可以引入別人的模塊;別人也可以引用你的這個py文件,去使用你寫的函數 。所以,模塊中可以有函數,也可以有類

導入一個模塊,使用import。

1.7 pyo文件

python -O -m py_compile file.py

可以編譯成pyo文件,是優化過的字節碼文件。
1. 其中的 -m 相當於腳本中的import,這裏的-m py_compile 相當於上面的 import py_compile 
2. -O 如果改成 -OO 則是刪除相應的 pyo文件,具體幫助可以在控制檯輸入 python -h 查看

總結

  • Python的pyc文件從一定意義上可以減少解釋器解釋Python文件的時間,不必每次都要解釋編譯一遍,方便下次快速加載,有點類似數據庫的緩存吧;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章