簡單的說它就是一個從源代碼編譯而來的中間文件(用于不同操作系統(tǒng)平臺的解釋器執(zhí)行)。比如,a說日語,b說中文,溝通起來不暢通,請一個翻譯,把a和b的語言都翻譯成英語,這個英語就可以理解成bytecode,一種中間語言。
bytecode的好處就是加載快,而且可以跨平臺,同樣一份bytecode,只要有操作系統(tǒng)平臺上有相應(yīng)的Python解釋器,就可以執(zhí)行,而不需要源代碼。不同版本的Python編譯的字節(jié)碼是不兼容的,Python2.6編譯的bytecode拿到Python2.7上去執(zhí)行就不行了。
如何生成字節(jié)碼?
Python解釋器一般會自動把.py文件轉(zhuǎn)換成bytecode,然后再執(zhí)行它。當(dāng)你第一次把.py文件當(dāng)作module導(dǎo)入,或者對應(yīng)的.py文件比.pyc文件的修改時間還要新時,Python解釋器都會再從sourcecode生成相應(yīng)的新bytecode。這樣當(dāng)你下次再次運行程序時,就會直接從bytecode運行,從而節(jié)省便宜時間。
Ps:這里需要注意,有些情況bytecode并不會生成:
遇到目錄寫權(quán)限的問題時。(比如你編寫代碼和運行代碼使用的具有不同權(quán)限的用戶角色,Linux上很常見)
運行一個script并不會被當(dāng)成是import操作,所以可能也不會生成bytecode。(比如:你有個一個a.py的文件,其中在a.py里,你import了b.py,那么運行pythona.py后,會生成b.pyc,而不會生成a.pyc)
.pyc文件是什么?
Python源碼編譯的結(jié)果就是PyCodeObject,每個作用域會編譯出一個對應(yīng)的代碼對象,其中名為co_code的PyStringObject保存著代碼對象的字節(jié)碼。
一個Python源文件就是一個模塊。每個模塊頂層的代碼對象通過marshal序列化之后就得到了.pyc文件。marshal以little-endian字節(jié)序來序列化數(shù)據(jù)。
那嵌套于頂層作用域里面的那些作用域,例如函數(shù)、類的定義,它們對應(yīng)的代碼對象在哪里?它們每一個都乖乖的躺在上一層作用域的代碼對象的co_const(常量池)域里,所以其實頂層代碼對象已經(jīng)嵌套包含了底下其它作用域的代碼對象。
如何對.pyc文件文件進行反編譯?
python文件如果要發(fā)布的話,有時候還是難免想保護一下自己的源碼,有些人就直接編譯成了pyc文件,因為這樣既可以保留跨平臺的特性,又可以不能直接看到代碼,也看到網(wǎng)上很多人說為了保護自己的代碼可以編譯成pyc文件。
用pyc文件可以保護python代碼的想法其實是不正確的,pyc文件是可以很容易被反編譯的,比如說比較著名的uncompyle6庫(https://github.com/rocky/python-uncompyle6),用來反編譯文件最爽不過了,幾乎支持python全版本的pyc文件的反編譯。
為什么要做代碼分析?
一般來說,代碼分析重要性的判斷比較主觀,不同的人有不同的認識。Python是用C來實現(xiàn)的,所以對于Python的性能或代碼質(zhì)量的評估可以通過dis模塊獲取到對應(yīng)的字節(jié)碼指令來進行評估。
一般來說一個Python語句會對應(yīng)若干字節(jié)碼指令,Python的字節(jié)碼是一種類似匯編指令的中間語言,但是一個字節(jié)碼指令并不是對應(yīng)一個機器指令(二進制指令),而是對應(yīng)一段C代碼,而不同的指令的性能不同,所以不能單獨通過指令數(shù)量來判斷代碼的性能,而是要通過查看調(diào)用比較頻繁的指令的代碼來確認一段程序的性能。
一個Python的程序會有若干代碼塊組成,例如一個Python文件會是一個代碼塊,一個類,一個函數(shù)都是一個代碼塊,一個代碼塊會對應(yīng)一個運行的上下文環(huán)境以及一系列的字節(jié)碼指令。
dis模塊主要是用來分析字節(jié)碼的一個內(nèi)置模塊。dis模塊的文檔可以讓你遍歷它的內(nèi)容,并且提供一個字節(jié)碼指令能夠做什么和有什么樣的參數(shù)的完整清單。
以上內(nèi)容為大家介紹了python之什么是字節(jié)碼(bytecode)?希望對大家有所幫助,如果想要了解更多Python相關(guān)知識,請關(guān)注IT培訓(xùn)機構(gòu):千鋒教育。http://m.fengjieshuijing.cn/