爲何有這麼多 Python版本

Python是出類拔萃的html

然而,這是一句很是模棱兩可的話。這裏的"Python"到底指的是什麼? 是Python的抽象接口嗎?是Python的通用實現CPython嗎(不要把CPython跟Cython搞混了)?亦或者指的徹底是其餘的東西呢?可能我另外指的是Jython,或者IronPython,或者是PyPy。也或者轉而談論的又是RPython或者RubyPython(這二者是徹底不一樣的東西)。java

上面提到的那些技術常常被提起和引用, 它們的使用目的和場景是徹底不同的(至少,它們的操做方式是徹底不同的)python

自從我使用Python工做以來,我已經用過了各類各樣的.*ython工具了。可是直到最近我才花時間去理解到底它們是幹嗎的,它們是怎樣工做的,爲何它們是不可或缺的。web

在這篇文章裏面,我會介紹各類Python的實現,最後以對PyPy的介紹結尾, 由於我我的認爲它是Python的將來。數據庫

全部的都從理解什麼是"Python"開始。編程

若是你對機器碼,虛擬機之類的很熟了,你能夠跳過開頭,直接從 "即時編譯: PyPy和它的將來" 這部分開始看起。瀏覽器

Python是解釋型的仍是編譯型的?

這是個Python新人都會迷惑的問題。緩存

首先須要明瞭的是Python只是一個接口。有一個關於Python應該作什麼以及怎麼作的具體說明(就像其餘任何接口同樣 ),而且對應的有不少具體的實現(也像其餘接口同樣)。安全

其次須要知道的是「解釋型」和「編譯型」是具體實現的特性,而不是接口的特性。ruby

因此,這個問題自己就沒有組織好。

Python是解釋型仍是編譯型的?這個問題真的沒有組織好。

對使用最普遍的實現(CPython:用C實現的,一般簡單的說成Python,若你不知道我所說的這些,那很肯能你在使用的就是CPython)而言,這個問題的答案是:解釋型,但帶有一些編譯型特徵。CPython把Python源碼編譯*成字節碼,以後再解釋這些字節碼,執行之。

*注意:這個編譯不是一般意義上的編譯。一般咱們說的編譯,是指把高級語言代碼轉換成機器碼。但這裏的編譯其實是另外一種意義上的編譯。(譯者,這句話不是很懂,原文是it is a ‘compilation’ of sorts,不知做何解,求教各位讀者。)

再詳細看下上面的答案吧,這有助於咱們理解本文中後面會講到的幾個概念。

字節碼 vs. 機器碼

瞭解字節碼和機器碼(或者native code)的區別是很重要的,最好的辦法或許是看看例子:

  • C代碼被編譯成機器碼,將在處理器上直接執行。每一條指令控制CPU工做。
  • Java代碼被編譯成字節碼,將在Java虛擬機(JVM)這個抽象的計算機上執行。每一條指令由JVM處理,JVM同計算機自己之間交互。

簡而言之:機器碼快的多,但字節碼更易遷移,也更安全。

機器碼隨機器的變化而變化,但字節碼在全部的機器上都是同樣的。有人可能會認爲機器碼是對特定環境優化了的。

  1. 回到CPython,工具鏈的執行過程以下:
  2. CPython編譯你的Python源代碼,生成字節碼。

字節碼隨後在CPython虛擬機上執行。

初學者經常由於看到.pyc文件而假設Python是編譯型的。這也有一些合理性:.pyc文件正式以後要解釋的字節碼文件。因此,你若以前運行過你的Python代碼,生成了.pyc文件,再次運行時就要快得多,由於不須要再次編譯生成字節碼了。

可選的虛擬機:Jython,IronPython等

正如我以前所述,Python有不少實現。前面也提到,CPython是最通用的。這是一個用C實現的,被認爲是」默認「的實現。

但其餘的呢?其中最顯赫的之一就是Jython,一個用Java實現的採用了JVM的實現。CPython生成在CPython虛擬機上運行的字節碼,而Jython生成在JVM上運行的java字節碼(這同編譯Java程序生成java字節碼的過程是同樣的)。

」爲啥你要用其餘的實現?」,你可能會如此發問。好吧,對開發者而言,不一樣的實現對不一樣的技術難題的支持程度不同。

CPython中很容易爲你的Python代碼寫C擴展,由於最終都是由C解釋器執行的。另外一方面,Jython則使得和其餘java程序共同工做很容易:無需其餘工做,你就可導入任何Java類,在你的Jython程序中使用其餘Java類。(題外話,若你沒有認真思考,這一段會很難。此時咱們已經在討論把不一樣語言的代碼混在一塊兒,並編譯成同一程序。(Rostin 提出混合Fortran和C代碼編程已經有一段時間了。因此,這並不新鮮,但仍然很酷。))

下面是一個例子,一段合法的Jython代碼:

?
1
2
3
4
5
6
7
[Java HotSpot(TM) 64 - Bit Server VM (Apple Inc.)] on java1. 6.0_51
>>> from java.util import HashSet
>>> s = HashSet( 5 )
>>> s.add( "Foo" )
>>> s.add( "Bar" )
>>> s
[Foo, Bar]
IronPython是另外一很流行的Python 實現,徹底用C#實現,針對.NET平臺。她運行在能夠叫作.NET虛擬機的平臺上,這是微軟的 Common Language Runtime (CLR),同JVM相對應。

你可能會說,Jython:Java::IronPython:C#。它們各自運行在相同的虛擬機上,你能從你的IronPython中導入C#的類,從你寫的Jython代碼中帶入Java類,等等

你徹底能夠不用任何非CPython的實現就能完成你手上的任何工做。可是使用這些技術也是有不少的好處的,大部分取決於你如今所使用的技術棧。 你使用了不少基於JVM的語言?Jython就是爲你準備的。使用的都是.NET世界的語言?那麼你應該試試IronPython了(或許你已經在用了)

順便說一下(儘管這不是使用不一樣的實現的理由),注意Python的各類實如今對待你的Python源碼的時候所作的處理方式是徹底不同的。而後這些差別是很小的,因爲這些實現都在不停的發展改進中,隨着時間的推移,這些差別會慢慢融合和兼容。好比,IronPython默認狀況下使用Unicode字符串,可是在2.x版本的CPython中默認是ASCII字符串(若是使用了非ASCII字符串,會拋出一個UnicodeEncodeError錯誤),可是在3.x版本里面CPythong已經默認支持Unicode字符串了。

即時編譯: PyPy和它的將來

咱們已經有了一個使用C寫的Python實現,一個用Java寫的,一個用C#寫的。接下來就是:用Python寫的Python實現(有心人可能會注意這句話有點問題,是個死循環,^_^)

接下來咱們看下什麼地方容易搞混淆。首先,咱們討論下即時編譯器JIT

JIT: 爲何會有這個?它的原理是什麼?

你們都知道本地機器碼的速度比字節碼的速度快不少。那麼,若是咱們能將一些字節碼直接編譯成本地機器碼再去運行它會怎樣呢?咱們必須花費一些代價(好比時間)在編譯字節碼到本地機器碼上,若是最終的運行時間更快,那麼這個代價就是值得的。這就是JIT編譯器的動機,一種混合瞭解釋器和編譯器好處的技術。簡單來說,JIT就是想經過編譯技術提高腳本解釋器系統的速度。

例如, 被JIT(及時編譯)採用的通用方法:

  1. 標識被常常執行的字節碼。
  2. 把其編譯成本地的機器碼。
  3. 緩存該結果。
  4. 當一樣的的字節碼再次被執行的時候,會取預編譯的機器碼,獲得好處(例如速度提高)。

這是關於PyPy的用處: 把JIT代入Python語言 (參看前面成果的附錄).固然也有其餘目的: PyPy 目標是成爲一個跨平臺,輕內存,支持stackless(譯註:stackless爲python提供微線程擴展,具備併發特性)。 可是及時編譯纔是它真正的賣點。 基於一系列時間測試的平均, 聽說性能上能提升6.27倍. 停一下, 看看下面這個由PyPy Speed Center提供的圖表:

PyPy is Hard to Understand

PyPy具備巨大的潛力,在這一點上,它與CPython高度兼容因此它能運行Flask,Django等等)。

但關於PyPy有許多困惑 (例如,荒謬的建議創造一種PyPyPy…語言). 按個人觀點,那主要是由於PyPy其實是兩種東西:

一種用RPython (非Python (我以前撒謊了))編寫的Python解釋器。 RPython是Python的子集,具備靜態類型。在Python裏,最難嚴格推論類型 (爲何這麼困難,考慮下下面的事實:

?
1
x = random.choice([ 1 , "foo" ])
  1. 將是合法的Python代碼 (歸功於 Ademan). x的類型是什麼? 咱們怎麼推出變量的類型,當類型尚未被嚴格實施?)經過RPython,你犧牲了一些靈活性, 但使得內存管理和優化大大的容易。

  2. 一個編譯RPython代碼爲了各類目標和加入及時編譯的編譯器。 默認平臺是C,也就是從RPython到C編譯器,但你也能夠瞄準JVM或者其餘。

只爲清晰,我將引用這些PyPy(1)和PyPy(2)。

爲何你在同一層面下同時須要這二者? 你能夠這樣想一下:PyPy(1)是一個用RPython寫的解釋器,所以它能加載用戶的Python代碼並將它編譯成字節碼。可是這個用RPython寫的解釋器自己要能運行,就必需要被另一個Python實現去解釋,對不?

咱們能夠直接用CPython去運行這個解釋器。可是這個還不夠快

取而代之,咱們使用了PyPy(2)(參考 RPython的工具鏈)去編譯這個PyPy的解釋器,生成其餘平臺(好比C, JVM或CLI)代碼在咱們的機器上運行,而且還加入了JIT特性。這個很神奇:PyPy動態的將JIT加入一個解釋器,生成它本身編譯器!(這就是核心原理:咱們在編譯一個解釋器,並同時加入了另一個單獨的編譯器到裏面去)。

最終結果就是一個融合了JIT優化特性的單獨的可執行文件,用來解釋執行咱們的Python源代碼。這就是咱們以前想要達到的效果。這麼講可能比較拗口,下面這張圖可能會解釋的比較清楚點:

再次重申下,PyPy真正難得之處在於咱們能夠利用RPython實現各類不一樣的Python解釋器,不用去關心JIT(除了一些小的提示外)。PyPy到時候會利用RPython工具鏈/PyPy(2)爲咱們自動實現JIT

事實上,咱們還能夠更抽象一點,咱們理論上能夠寫一個適用於任何語言的解釋器,而後將它扔給PyPy,最後得到那種語言的JIT。緣由是PyPy僅僅關心的是優化解釋器,而不會去關心這個解釋器到底解釋的是什麼語言。

理論上你本身能夠寫一個適用於任何語言的解釋器,而後將這個解釋器傳給PyPy,最後你獲得這個語言的一個JIT。一個簡單的題外話,我這裏想提一下,JIT本事是至關棒的。它使用了一種叫作跟蹤的技術,按照下面的步驟執行:

  1. 執行解釋器並解釋執行全部代碼(尚未加入JIT特性)
  2. 對被解釋過的代碼作一些記錄
  3. 確認你已經執行過的操
  4. 將確認過的這些代碼編譯成本地機器碼

想獲取更多信息,能夠參考這篇文章,易於理解,而且很是有趣

最後收尾:咱們使用PyPy的RPython-to-C(或者其餘目標平臺)編譯器去編譯PyPy的基於RPython實現的解釋器。

結尾

爲何它如此的偉大?爲何這個瘋狂的想法值得咱們去追求?我想Alex Gaynor已經在他的博客上面作了很好的解釋了:「[PyPy就是將來] 由於[它]提供了更快的速度,更大的靈活性,而且對於Python的成長也提供了一個更好的平臺」

總之:

  • 它很快,由於它將源代碼編譯成了本地機器碼(使用了JIT)
  • 它很靈活,由於除了極少數的額外工做須要作外,它就能將JIT加入你的解釋器中
  • 它仍是很靈活,由於你能使用RPython實現你的解釋器,這個比其餘的(好比C語言)更易擴展。事實上,它是如此的簡單,這裏有一篇教程教你如何實現你本身的解釋器

附錄: 其餘一些你可能已經聽過的名字

  • Python 3000 (Py3k): Python 3.0的一個別名,2008年釋出的一個主要版本,可是它並不向後兼容.。Py3k團隊預測這個版本被徹底採用可能須要5年時間.。如今絕大多數(注意:這個是江湖傳聞)Python開發者繼續在使用2.x版本,不過如今人們愈來愈多的對Py3k開始關心了。

  • Cython: 一個Python的超集,可以調用C語言的函數
    • 目標: 容許你爲你的Python代碼寫C擴展
    • 容許你爲你的Python代碼加入靜態類型,運行編譯並達到接近C語言的性能。
    • 這個跟PyPy比較相似,可是不是同樣的。使用這個的時候,在提交給編譯器以前必須用戶代碼裏面寫好這些特殊代碼。若是使用PyPy的話,你寫的仍是普通形式的Python代碼,編譯器會幫你處理一切優化的工做。
  • Numba: 將JIT加入到被註解的Python代碼中,簡單來說就是,你給它一些提示,它就會優化加速你這段代碼。Numba是Anaconda發行版(一系列數據分析和管理的軟件包)的一部分。

  • IPython: 跟咱們討論過的其餘版本徹底不同。這是一個Python的計算環境。爲一些GUI工具集和瀏覽器體驗等提供支持。

  • Psyco: 一個Python的擴展模塊,也是早先的一種Python JIT的成果。 然而,它已經被標註爲「中止維護和死亡」了。事實上,Psyco的首席開發者Armin Rigo如今在爲PyPy工做。
其它翻譯版本(1)

語言綁定

  • RubyPython: Ruby和Python虛擬機的一座橋樑。容許你在你的Ruby代碼中嵌入Python代碼。你定義Python的起始位置,而後RubyPython負責在不一樣VM直接傳遞整理數據。

  • PyObjc: Python和Objective-C語言直接的橋樑。實際上,這意味着你能在你的Python代碼中使用Objective-C的庫(包括建立一個OS X應用程序所須要的一切),反過來在Objective-C裏面也可使用Python的模塊。這樣的話,CPython用C語言來實現就很方便了,由於C語言是Objective-C的一個子集。

  • PyQt: 同PyObjc幫你綁定OS X GUI組件相似,PyQt幫你綁定Qt應用程序框架,讓你能夠建立豐富的圖形界面,訪問關係數據庫等等。另外的一個旨在幫你簡化從Python到另外的框架的工具。 

JavaScript 框架

  • pyjs (Pyjamas): Python中一個建立web和桌面應用程序的框架。包含一個Python-to-JavaScript的編譯器和其餘一些工具。

  • Brython: 一個使用JavaScript語言寫的Python虛擬機,可讓Py2k 代碼在瀏覽器中執行。

 

出處:http://www.oschina.net/translate/why-are-there-so-many-pythons

相關文章
相關標籤/搜索