原文: https://wiki.python.org/moin/Python2orPython3
在項目開發中,我應該用python2還是python3?
它們之間有什么區別?
簡而言之,python2.x是過去;python3.x是現在、是將來。
在2008年的時候,python3.0發布。python2.x的最后版--v2.7也于2010年年中發布,并且聲明了對最后一版的延長支持。在這之后,python2.x分支就沒有任何主要的新屬性發布。3.x版本一直持續開發,并且已經發布了5年的穩定版本。2012年發布3.3,2014年發布3.4,2015年發布3.5,2016年發布3.6。這意味著新開發的標準庫只在python3.x中展現。
在最新的2.x發布版本中,Guido van Rossum(python的創造者)決定適當的清理python2.x,以減少向后兼容性。最大的改變是更好的unicode編碼支持(默認情況下所有文字都轉換成unicode)與更加健全的bytes/unicode編碼分離。
此外,在幾個核心語言層面,做了一些調整(如,print與exec是聲明,整數使用向下取整)。這些改變對初學者來說,更加容易學習。對Python其他部分也更加易用。一些老舊的丑陋的代碼被移除,舉個例子,所有的類都是new-style,"range"函數不再像python2.x一樣返回list, 而是返回一個內存利用率高的迭代器。
《python3.0中的新特性》對于主要的語言層改變以及與python2.x源碼可能存在的兼用性做了一個很好的概述。Nick Coghlan(CPython開發者之一)也創建了一個relatively extensive FAQ來處理python版本過渡問題。
然而,在過去的時間里,龐大的python生態系統已經累積了大量的重要的高質量的軟件。對python3.x的兼容的最大問題就是,某些軟件(尤其是一些公司內部軟件)任然不能再python3.x下正常運行。
該如何選擇我要使用的版本?
如何選擇版本,主要依賴于你想要做什么。
如果你明確的知道用python3想要做什么。很好,這里有少許次要的缺陷或不足,如不是太嚴重的軟件庫支持問題,還有一個客觀事實是,現在的很多linux發行版和mac都是將python2作為默認python版本(雖然在很多系統中,python3也被安裝了),python3有著一個語言應該有的所有特性。如果你能控制你所安裝的環境并且你明確知道你不需要python2的模塊,使用python3是一個很好的選擇。現在,很多的linux發行版已經內置了python3。并且所有這些都適用于終端用戶。一些linux已經開始淘汰python2作為內置python版本。
特別指出的是,很多教師或書籍在介紹python的時候都會首先考慮python3,而后,如果有必要,再介紹python3與python2的不同之處。因為python3移除了一些,初學者學習python2而踩的一些不必要的坑。
然而,任然有一些問題需要你必須用python2而不是用python3。
- 你的應用所部署的環境是一個你不能控制的。這個環境中使用了特殊版本的python,而不是讓你自由選擇python版本。
- 你依賴的三方庫沒有兼容python3。并且這個庫是一個不可或缺或及其重要的庫。
python3在使用創建GUI應用已經得到了廣泛的支持。包Tkinter作為標準庫。從python3發布開始,PyQt也被支持。 在2011年,PySide被支持。PyGObject作為PyGtk的替代品也被支持。
這里列舉了一些主要的支持python3的包:
- NumPy 與 SciPy(科學計算)
- Django、Flask、CherryPy、Pyramid(web開發)
- Pyramid(圖片處理,代替PIL)
- cx_Freeze(將python文件打包成可執行文件)
- py2exe(打包成window可執行文件)
- OpenCV 3(開源的機器學習與計算機圖形庫)
- requests(http請求庫)
- lxml(python xml解析庫)
- BeautifulSoup4(html dom解析庫)
- ipython與jupyter(交互計算)
- 等等
如果你想使用python3,但是你又害怕依賴兼容性問題。使用之前,做一些調研是值得的。這是一個持續跟進的過程,這篇wiki也可能過時。此外,有著對于python2.6+與python3.3+的大量支持,現在很多的python代碼都不需要做較大的修改就可以運行在python3上。尤其是用于web與GUI框架的代碼,這些框架強制應用區別二進制數據與文本(six compatiblility module可以用來修補這些問題)。
雖然官方文檔與tutorial對python3鏡像完整的更新。但是在網上與一些相關的書籍中的大量的文檔是使用python2。這些文檔雖然也在不斷的更新。當用python3來運行的時候需要做一些調整。
有些人不想用python3。這是他們的權利。畢竟是少數人。
如果你想用其他一些python執行環境,如IronPython,Jython 或Pyston等等,使用python3是不值得的。在這些平臺中python3的支持還是不太理想。當你應為系統的完整性或性能等等原因而選擇前面所說的執行環境的時候,這個因素(在這些平臺上,python3支持有限)將會影響你。
難道我不想避免使用python2? python2是一門有許多錯誤的老語言了,python已經開了一個主版本來移除這些錯誤。
good, 也不完全是,一些python3.0,python3.1的斷層式的修改已經各自被移植到python2.6, 2.7。更多的移植相關,參見What's New in Python2.6與What's New in Python2.7
對于哪些屬性只能用在python3與哪些屬性不能移植到python2沒有一個詳盡的列表列出。
- 字符串默認編碼為Unicode
- 清除unicode與bytes分離
- 異常鏈
- 函數注解
- 關鍵詞參數語法
- 擴展的tuple解包
- 沒有局部變量定義
語言版本的更迭,并沒有限制核心代碼的改變。在標準庫中,一些在python3中的改善并沒有直接移植到python2。參見What's New in Python3。一些標準庫的提升可以通過PyPI找到。
也就是說,用python2寫的代碼更加像python3的代碼。這可以代表很多事情。包括使用新類型的classe,不使用古老的棄用的print用法,使用懶加載的迭代器。舉個例子,好的python2代碼會用xrange來代替range。xrange最開始在python3上的range實現(當然,range在python3中表現更好一些,因為他可以handle住超過sys.maxint的值)。有點值得注意的是xrange()在python3中沒有被定義。
最終要的是,python2或python3只是些小問題,你真正應該做的是寫好好代碼。這些代碼包含完整的單元測試,正確的使用unicode。(在unicode與bytes問題上,python3相對于python2更少的操心。這是一件好事情,雖然這讓一些軟件包的移植變得相對來說比較惡心)
我想用Python3,但是想用的一些庫只有python2。難道我只能不得不重新回去使用python2或者放棄使用這個庫?
假設你找不到在python3中支持替代包,你可以看看下面的幾種建議:
- 移植這個庫到python3 ("porting"意味著你需要讓這個庫能正常的在python3上運行)
- 如果實在是實現比較困難,并且你的其他依賴也是用python2,你可以開始的時候用python2。隨著庫在其他地方被移植的,一旦每一個依賴庫度偶做好了移植,好的python2代碼可以進行輕松的切換。
- 好好想想這個庫是否真的很重要?或許你可以不使用它。
最理想的狀態是你試著移植到python3,你經常發現有人使用它,即使不是當前庫,其他成員通常會感激你的。尤其是移植中發現原始的bug。這樣做可以提高原始版本與python3移植版本的質量。移植不是一帆風順的,但總是比你自己從頭開始寫容易。
在Python2 porting guide中,你可以知道如何移植庫。最基本的思想是使用python2庫,在python2中使用-3 命令切換,檢查所有的單元測試通過,而沒有警告。如果測試失敗,或者發出了警告信息。修改源碼,再一次做單元測試(這可能需要在老的版本中降低兼容性)。當沒有警告信息的時候,可以試著用python3運行這個庫了。最好的可能的狀態是運行的代碼是python2,python3兼容的,這時候,移植完成。
如果在python3中,單元測試任然失敗。那么標準庫中的2to3組件能夠自動生成運行在python3下的版本。或者Armin Ronacher的python-modernize組件可以用于python2.6+和3.2+或者3.3+(這依賴于命令行輸出參數)。如果你使用python-modernize,同樣需要在Python2下做單元測試。
任一種方法都可以從單個python2代碼庫并行支持python2和python3。將python2與python3分開維護更加容易一些。(可以問問核心代碼開發者,他們這么做已經很多年了)
如果自動轉換后,測試失敗,有可能是因為python3與python2的語義變化。這些變化有可能導致轉換器自動轉換失敗,-3 switch也沒有檢測出來。這些問題不多,但是也是存在的。當你遇到的時候,提交一個bug給CPython,請求一個新的 -3 警告,是非常值得的。
如果包含c擴展或者工程沒有使用想CPython,cffi,SWIG這些能夠值得處理python2與python3之間的差異的包裹生成器,移植過程可能更加復雜。但是還是會比你自己開發相同功能的包更容易一些。extension porting guide介紹了一些它們之間的主要的不同之處。
這里是一些比較深入的guide:PortingPythonToPy3k,PortingExtensionModulesToPy3k
我想用python3寫一些東西,但是有些人只用python2,我該怎么辦?
除了有能夠從python2代碼生成python3代碼的2to3工具,還有轉換python3代碼到python2代碼的3to2工具。理論上,可以3to2可能比2to3工作得更好,因為python3對轉換器轉換來數,清理掉了許多惡心的死角問題(畢竟,盡可能擺脫更多的這種問題是打破向后兼容性的主要原因之一)。然而,那些嚴重依賴python3特有屬性的代碼(例如函數注解,擴展版tuple unpacking)是不可能轉換成功的。
可以舉個恰當的比方,3to2相對于2to3來說是一條更少旅人的路你可能遇到一些邊邊角角。如果你想用python3, 這些是值得探索的。
在一些通用模塊代碼中支持python2與python3
python2.6+與python3.3+有大量的相同之處。例如,在python3中對unicode字符串前面加'u'字符的恢復意味著語義上正確的python2.6+代碼可以與python3.3+兼容,同時保留著大量的慣用的python。主要的不同是來自不同地方的代碼需要被修改,這樣才可以處理python2與python3之間的命名問題。
因此,six compatibility package是在單一庫中支持python2與python3最主要的實用程序。
future compatibility package任然在測試中,并且不像six包一樣支持如此多的python版本(future只支持到python2.6, six可以支持到python2.4)。但是future運行python2兼容代碼可以寫得跟python3通用代碼一樣的風格(例如,它包含了python2兼容python3中bytes類型實現代碼,而不是依賴于python2中的字節字符串類型,他們兩個是不同的API)。
其他一些確定標準庫的主要的因素是是否存在一個更新的對PyPi的移植,這些移植優先用于python2標準庫。下面所列的這些模塊要么是對PyPI的移植,要么是原生支持python2.7與python3標準庫:
- unittest2(Michael Foord, 標準庫unittest維護者, 需要2.6支持)
- mock(Michael Foord, 標準庫unittest.mock維護者)
- contextlib2(Nick Coghlan, 標準庫contextlib維護者)
- configparser(?ukasz Langa, 標準庫configparser維護者)
- futures(Alex Gr?nholm and Brian Quinlan, 標準庫concurrent.futures維護者)
- argparse(Steven Bethard, 標準庫argparse維護者, 需要2.6支持)
- faulthandler(Victor Stinner,標準庫faulthandler維護者)
- cdecimal(Stefan Krah, 標準庫decimal維護者)
- ipaddr((Peter Moody, 標準庫ipaddress維護者)
- stats(Steven D'Aprano, 標準庫statistics維護者)
- enum34(Ethan Furman,標準庫enum維護者)
- funcsigs(Aaron Iles,移植于函數signature objects)
- shared namespace module for backports(Brandon Craig Rhodes)
- backports.inspect(Tripp Lilley, 額外的inspect移植,基于funcsigs)
- backports.datetime_timestamp(Jason R. Coombs, datetime.timestamp的移植)
- backports.pbkdf2(Christian Heimes, 標準庫hashlib維護者, 對hashlib.pbkdf2_hmac的移植)
- backports.ssl_match_hostname(Brandom Craig Rhodes 與 Toshio Kuratomi, ssl.match_hostname的移植)
- backports.lzma(Peter Cock, lzma wrapper模塊的移植)
- lzmaffi(Tomer Chachamu, lzma的移植)
- tracemalloc(Victor Stinner, 標準庫tracemalloc的維護者)
- pathlib(Antoine Pitrou, 標準庫pathlib的維護者)
- selectors34(Berker Peksag,標準庫selectors的移植)
當在交叉版本的標準庫之間使用,使用移植版本的命名空間模塊可以清楚的指明。原始版本的屬性可以使用而不會產生沖突。
下面的模塊不是移植版本。但是可以替換標準版本的各個版本兼容的庫。
- requests(對http/https更高級封裝的api)
- regex(一個替代的正則表達式引擎)
- lxml.etree(ElementTree XML API的替代實現)
上面的這些模塊也支持python2。在python3.4中,asyncio模塊被添加到標準庫中。
- asyncio(Guido van Rossum, BDFL and標準庫 asyncio維護者)
其他一些有助于在python2,python3做選擇的資源
- Community Web site to promote Python 3
- Nick Efford 關于使用python3教學的一些點評
- Mark Pilgrim 所寫Python3版的《Dive Into Python》,http://getpython3.com/diveintopython3/
- Swaroop C H 的《A Byte of Python》python3版本,http://www.swaroopch.com/notes/Python
- What an IronPython user should know about Python 3
- Paul Barry的Head First into Python 3
- Mark Summerfield所寫的關于python2與python3不同的文章:Moving from Python 2 to Python 3
- Wesley Chun所寫的關于python3的兩篇文章:Python 3: the Evolution of a Programming Language (Mar 2009) 與Python's "New" Division: Python 2 Versus Python 3 (Jan 2010)
- Wesley Chun的Python 3: the Next Generation talk & slides
- James Bennett 的一篇有趣的討論:why Python 3.0 exists at all
- how to get Unicode versus bytes semantics in 2.x similar to the ones in 3.x
- Nick Coghlan 的關于python3的問答:Q&A
補充說明
- 任然在維護的包:https://python3wos.appspot.com/
- 主要的linux系統將python鏈接到python3, Ubuntu與Fedora設置為默認值:https://wiki.ubuntu.com/Python/3與https://fedoraproject.org/wiki/Changes/Python_3_as_Default