如果我編寫一個python腳本,任何人都可以簡單地將一個編輯器指向它並閱讀它。但對於使用C語言編寫的程序,必須使用反編譯器和十六進制表等。這是爲什麼?我的意思是我根本無法打開Safari瀏覽器並查看其代碼。爲什麼C程序需要反編譯器,但python程序不需要?
回答
注意:作者拒絕在這個主題的深厚專業知識。有些斷言可能不正確。
Python實際上被編譯成字節碼,這是python解釋器運行的東西。無論何時使用Python模塊,Python都會生成一個.pyc
文件,其名稱對應於該模塊。這相當於編譯C文件時生成的.o
文件。
所以,如果你想要的東西拆開,將.pyc
文件將是吧:)
了Python經過時編譯一個模塊是非常類似於gcc
或其他C編譯器C源代碼的代碼做的過程。主要區別在於它作爲文件執行的一部分透明地進行。它也是可選的:在運行非模塊(即最終用戶腳本)時,Python只會解釋代碼而不是先編譯它。
所以真的你的問題是「爲什麼python程序是以源代碼而不是以編譯模塊的形式發佈的?」換句話說,「爲什麼C應用程序是作爲編譯的二進制文件而不是源代碼來分發的?」
它曾經是非常普遍的C應用程序作爲源代碼分發。這是在操作系統及其各種子實體(即Linux發行版)變得更加成熟之前回來的。一些發行版,例如gentoo,仍然將應用程序分發爲源代碼。應用程序有點尖端或模糊,仍然作爲它們所針對的所有平臺的源代碼分發。
原因是兼容性和依賴性。您可以在Mac上運行預編譯的二進制Safari,或者在Ubuntu Linux上運行Firefox,原因是它專門爲該操作系統,體系結構(例如x86_64)和庫集合構建。
不幸的是,編譯大型應用程序相當緩慢,每次應用程序更新時都需要至少部分重做。因此二元分佈的動機。
那麼,爲什麼不創建一個Python的二進制分佈?首先,正如Aaron mentions,模塊需要重新編譯每個新版本的Python字節碼。但這與重建C應用程序以鏈接動態庫的新版本類似 - 在這種意義上,Python庫與C庫類似。
真正的原因是Python編譯比C編譯快得多。我認爲這部分是由於該語言的動態性質,也因爲它不像編譯過程那麼徹底。這有其折衷:特別是,Python應用程序的運行速度遠遠超過C程序,因爲Python必須將編譯的字節碼解釋爲處理器的指令,而C應用程序已經包含這些指令。
所有人都說,有一個名爲py2exe的程序,它將採用Python模塊和發行版並構建預編譯的Windows可執行文件,其中包括模塊及其依賴項的邏輯(包括Python本身)。我想這一點是爲了避免強制人們在他們的Windows系統上安裝Python來運行你的應用程序。在Linux下,或者我認爲甚至OS/X,Python通常已經安裝,所以預編譯並不是真的必要。 Linux系統也有超級包管理器,如果它們尚未安裝,它們將透明地安裝諸如Python之類的依賴項。
Python是一種腳本語言,通過中間人在虛擬機中運行。 C是一種編譯語言,將代碼編譯爲二進制代碼,計算機可以在沒有所需的額外東西的情況下運行該代碼。
是否有可能編譯python到一個可執行的二進制文件,然後簡單地分發? – Ali 2010-10-06 04:33:23
@Ali:不,沒有合理的方式去做,不要相信別的。 – 2010-10-06 04:45:31
因爲C代碼符合對象(機器)代碼,並且python代碼被編譯爲中間字節代碼。我不確定你是否指的是python的字節碼 - 你必須引用可直接執行的源文件本身(隱藏你的字節碼!)。 C需要編譯和鏈接。
- Python腳本只有在運行時才被解析並轉換爲二進制文件 - 即它們是文本文件,您可以使用編輯器讀取它們。
- C代碼被編譯並鏈接到一個可執行的二進制文件,然後才能運行。通常,只有這個可執行的二進制文件是分佈式的 - 因此你需要一個反編譯器。你可以隨時查看源代碼,如果你有權訪問它。
您無法打開並閱讀實際爲python運行的代碼。嘗試
import dis
def foo():
for i in range(100):
print i
print dis.dis(foo)
這會顯示foo
程序的(人類可讀的)bytcode。等價地,您可以保存該文件並從交互式Python解釋器中導入它。這將創建一個.pyc
文件,其腳本具有相同的基本名稱。用十六進制編輯器打開它,然後查看實際的python字節碼。
不同之處在於,python在不同版本之間更改了字節碼,因此您需要爲每個版本的Python分發不同版本的二進制版本。這將是一個痛苦。
隨着C,它被編譯爲本地代碼,所以字節代碼更加穩定,使得只有二進制版本成爲可能。
這是一個很大的話題。你應該看看你當地友好的計算機科學課程,你會發現很多有關這個主題的偉大的東西。
簡短的答案是Python是一種「解釋」語言,這意味着它需要一個機器語言程序(python解釋器)來運行python程序,並添加一個間接層。 C或C++是不同的。它們直接編譯爲機器碼,可直接在處理器上運行。
然而,這裏有很多額外的伏都教。從技術上講,Python被編譯爲一個字節碼,而現代解釋器的編譯越來越多,所以編譯和解釋代碼之間的界限越來越模糊。
是的,你可以 - 它被稱爲反彙編,並允許你很好地看看Safari的代碼。問題是,C和其他語言一樣,編譯爲本地代碼,即CPU可以「理解」並執行的代碼。
或多或少顯然,CPU指令集中的抽象級別遠遠低於像Python這樣的高級語言。CPU指令不關心「下載該URI」,而是更多地「檢查該位是否設置在硬件寄存器中」。
因此,總之,在本機應用程序中出現的複雜程度在查看機器代碼時要高得多,因此很多人根本無法理解那裏發生的事情,很難獲得大的圖片。隨着經驗和時間的掌握,人們可能會一直這樣做,扭轉應用和所有情況。
然後可以編譯python到一個可執行的二進制文件,然後簡單地分發它? – Ali 2010-10-06 04:32:59
Python腳本與查看用英語(或他理解的語言)編寫的待辦事項列表的人類似。這個人必須完成所有的工作,每次都要完成這些事情。如果這個人不是每次都獨自完成這些步驟,而是創建並編程一個能夠一次又一次地執行這些步驟的機器人(並且可能比他更快),那麼這個機器人就類似於C程序。
python情況下的人稱爲「解釋器」,在C情況下稱爲「編譯器」,C機器人稱爲編譯程序/可執行文件。
當您查看python程序源代碼時,您會看到待辦事項列表。在機器人的情況下,你會看到齒輪,電機和電池等,這些與待辦事項列表看起來有很大不同。如果你能夠掌握C的「待辦事項」列表,它看起來有點像Python代碼,只是用不同的語言。
編譯Python腳本。它們只是爲僅存在於軟件中的機器編譯的。 Python的「解釋器」是該機器的一個模擬器,它具有一個嵌入式編譯器,並將其移植到頂層,以便將該腳本編譯爲該虛擬機器的目標代碼格式。 – 2010-10-06 04:44:18
非常感謝 - 我知道那些細節。假設問題提出者的代謝率適中,我可以很容易地進行消化。 – Rajan 2010-10-06 05:23:58
並非所有的C程序都需要反編譯器。有很多C代碼以源代碼形式分發。如果分發爲字節碼(.pyc文件),一些Python程序做需要反編譯器。
但是,就您的假設有效而言,這是因爲C是compiled language而Python是interpreted language。
python不僅僅是java的解釋性語言。它在虛擬機上運行。 – aaronasterling 2010-10-06 04:28:35
在你問到的幾個註釋中:「是否可以將python編譯爲可執行的二進制文件,然後簡單地分發它?
從理論的角度來看,毫無疑問答案是肯定的 - 一個Python程序可以被編譯成完全編譯的機器代碼,並且可以作爲完全編譯的機器代碼分發。
從實踐的角度來看,它有更多的問題。有一些東西,如Unladen Swallow,Psyco,Shed Skin和PyPy,你可能想知道。
Unladen Swallow主要是在製作的Python運行更快的嘗試,但部分計劃這樣做,包括使用LLVM其後端。 LLVM可以(除其他外)生成本機機器碼輸出。 Unladen Swallow的最後幾個版本使用LLVM進行本地代碼生成,但是 1)網站上的最新更新是從2009年底開始的,2)該版本的發行說明說:「Unladen Swallow團隊並不建議廣泛採用2009Q3版本。「
Psyco作爲一個基本上可以進行JIT編譯的Python插件,所以即使它可以加快執行速度(在某些情況下相當多),但它不會生成可分發的機器代碼可執行文件。總之,雖然它與你想要的類似,但並不打算按照你的要求去做。
Shed Skin Python-to-C++生成C++作爲其輸出,然後編譯C++並(可能)分發結果。 Shedskin目前在0.5版本 - 即沒有人聲稱它是一個完成的,發佈的產品。另一方面,開發正在進行中,每個版本似乎都包含相當大的改進。
PyPy是用Python編寫的Python實現。他們的意圖是允許代碼生成「插入」而不影響其餘的實現 - 但他們目前支持4種不同的代碼生成模型,我不相信它們中的任何一個會生成本地機器代碼直接在硬件上運行。
底線:工作已經完成,目前正在與做你問什麼的意圖完成,但至少據我所知,這不是真的什麼我可以合理建議作爲成品,你現在真的可以依靠做這項工作了。主要重點在於執行速度,而不是生成獨立的可執行文件。
G-WAN在運行時執行ANSI C腳本 - 就像Python腳本一樣。
這可以是服務器端腳本(使用G-WAN作爲Web服務器)或任何通用C程序,您可以鏈接任何現有的庫。
哦,和G-WAN C腳本比Python,PHP或Java快得多......
這與此有關嗎? – NullUserException 2010-10-06 15:28:09
- 1. 爲什麼Linux驅動程序需要編譯?
- 2. 爲什麼sensorManager.registerListener需要處理程序?
- 3. PIC反彙編程序需要
- 4. 編譯的程序需要參數?
- 5. 爲什麼XAML不需要編譯?
- 6. 編譯和運行GLSL程序需要什麼?
- 7. 爲什麼需要編譯Java代碼,但JavaScript代碼不需要
- 8. 需要幫助反編譯未知應用程序
- 9. 什麼是這個JavaScript程序需要
- 10. 我需要在我的構建服務器上編譯Silverlight 2.0應用程序需要什麼
- 11. 爲什麼在程序中主要需要
- 12. 我需要一個Java反編譯器
- 13. 爲什麼編譯器需要.java後綴但解釋器不需要.class後綴?
- 14. 無法編譯簡單的C++程序,需要澄清
- 15. 需要幫助瞭解C++程序的編譯
- 16. 需要幫助編譯Windows XP上的目標c程序
- 17. 爲什麼我們需要-static選項來編譯原生android應用程序
- 18. 爲什麼我需要glut.h,glut32.lib,glut32.dll ALL才能編譯openGL程序?
- 19. 爲什麼我需要FreeGLUT來編譯和鏈接一個GLFW程序
- 20. 爲什麼.NET Core應用程序需要C#和VB程序集?
- 21. 編寫彙編程序,需要幫助
- 22. Ruby需要'文件'不起作用,但需要'./file'。爲什麼?
- 23. 爲什麼bcrypt需要C++和Python?
- 24. 爲什麼Java應用程序需要應用程序服務器來託管?
- 25. 爲什麼JDBC驅動程序不需要H2
- 26. sigaction - 爲什麼我們不需要重置處理程序?
- 27. 爲什麼更新到DLL需要重新編譯,有時不需要?
- 28. 斯卡拉`應用程序並不需要parameters`編譯錯誤
- 29. 在asp.net應用程序中不需要預編譯
- 30. 程序需要重啓的程序是什麼?
應該有年齡段的標籤。 – Yehonatan 2010-10-06 04:47:09
@Yehonatan:我認爲收集所有關於編程的新手問題的標籤是一個好主意 – pyfunc 2010-10-06 05:03:49
@pyfunc:[管理層不同意。](http://blog.stackoverflow.com/2010/08/the-death-of-meta -tags /) – intuited 2010-10-06 05:18:29