如何評價 Python 3 打破向後兼容(Backward Compatibility)的決定?
最近Hacker News上面的討論:
https://news.ycombinator.com/item?id=6985207https://news.ycombinator.com/item?id=7799524從評論來看,社區的意見非常的兩級分化。有人認為Python 3的新特性值得肯定;也有一大份部分人覺得Python 3帶來的新特性不足以促使程序員進行遷移,打破向後兼容性更是一個敗招,增大了移植的成本,有些dev索性直接轉向其他語言,如Go和Node.js。那麼,為什麼Python 3從設計開始之初會做出打破向後兼容性的決定呢?是因為開發者個人的好惡,還是為了有設計上跟深層次的原因不得不做出取捨?歷史上有其他語言在打破了向後兼容性的情況下,依然得到平穩過渡的么?如果有,他們是如何做到的呢?
Python 3 作出的不兼容改動,我覺得對這門語言是有很大益處的。修正的地方其實是以前的設計失誤, 下面舉兩個最明顯的例子。首先是print由 statement 轉變為函數。看看這個語法:
print &>&> outfile, arg1, arg2
和新的語法
print(arg1, arg2, file=outfile)
在 Python 2, 當你想輸出不換行的時候, 要這樣, 在後面加一個逗號:
print arg1, arg2,
但這樣不可避免地會出現一個空格。
Python 3 裡面,解決了這個問題print(arg1, arg2, end="")
而且好處還有更多, 因為 Python 函數參數傳遞的表達能力很強,對print引入特殊語法反而約束了表達能力, 例如不能用 * 號展開參數。
第二個例子,當然是字元串的問題了, 相信用過 Python 2 的人都被decode, encode什麼的坑過。Python 2 裡面:bytes is str # True !!!
這坑爹呢!
在 Python 3 裡面, 通過把 str 分成 str 和 bytes 兩個概念,很好的解決了這個問題。str.encode, bytes.decode, 學習了 Python 3 甚至可以幫助你理解 Python 2 這個地方為什麼這麼坑, 這完全是個設計失誤,遲早要改的。反對匿名用戶的說法,Py3並不是開發者個人好惡影響~~~相反,我認為,Py3的升級,用「涅槃」二字形容,再合適不過。
話從頭說起就很長,我也不善此道,簡述之。
很久以前,Python只是一門腳本語言,地位類似於Perl,甚至shell、awk、sed之類,你看py2裡面的反引號``(像極了Perl里的反引號),及其虛擬機的構造(大循環,無JIT)可窺一二,一般意義上人們認為「腳本語言」是「游擊隊」,不堪大用。
後來Python社區經營多年,終見起色,在GUI開發、Web開發、乃至於近些年的大數據等領域,開始有了一些與傳統「正規軍」編程語言(各方面對比Java)一搏高下的資本,於是有為其「正名」想法的人越來越多,也越來越理所應當。
python想向「正規軍」發展,幾個困擾其發展的根本性問題亟待解決,如JIT、Sandbox、GIL等,此外,更需要戒除一些「游擊隊」時養成的不良習慣,大致有以下問題:
popen2,甚至是popen3這種命名方式,至於為什麼popen2這種命名不行,可百度 「史上最糟糕的兩個變數名」
print語句問題,「正規軍」裡頭,print可不能是關鍵字,這太掉價了Threading.Thread這種與其他標準庫命名風格不一的模塊,大致參考PEP8,閹掉不符合規定的unicode問題,str與byte混用的問題,得向java好生學學
「正規軍」怎麼能連個像樣點的sandbox都不提供呢(雖然py3也沒提供)~......由於需要解決的問題實在是太多,而有些問題(如JIT)則無可避免需要「傷筋動骨」(虛擬機乃至位元組碼格式需要改動),有些問題則無可避免需要破除向下兼容性(如蛋痛的模塊命名修改後,原有代碼無法運行),還有其他一些讓編程更方便的東東如unicode/byte等,語法形式上的改動也破除了向下兼容性。
所以,要想有個更好的發展,必須跟過去來個了斷,長痛不如短痛,所以,還是推到重來吧。誰都不想找蛋疼的!不兼容是權衡考慮以後的決斷,我覺得這個決斷是對的,可以成立的。
有的時候不是說想兼容就能兼容的,無限兼容就是無限的麻煩。
比如,windows 系統,至今你無法建立一個名字為 COM1 的文件夾。為什麼?就是為了保持兼容性。具體歷史原因可以去查資料。你覺得保持這樣的兼容對於一個不斷進步的操作系統來說是好是壞?
說的玄虛一點,哲學裡有個詞叫,揚棄,不拋棄舊的的東西就不能從根本上改變和進步。正好這兩天在讀Python的歷史-Python創建者在blogspot上面寫的博客,看到這個問題正好說說自己的想法。先回答問題:
首先是人就會犯錯,人的認知也會隨著時間發展而變化。編程語言也要發展,發展就不可能總是加法(C++試圖這樣發展)。Python的作者早就覺得Python裡面有些東西沒做對,有些東西沒做好,為什麼Python 3打破了後向兼容?沒什麼特別的,我們只是恰巧趕上了這時候,不是一時興起,這事情背後有至少幾年的思索了……
扯個遠的,我好像聽說90年代末期libc來了一次不向後兼容的更新,當時所有的應用程序都要重編才能適應新的libc。我相信當時的程序員心裡也是一萬頭草泥奔騰而過……然後打破後向兼容性和平穩過渡這兩件事兒本來就是一矛盾,我覺得沒人能做到,做到這個就好比是你剛學會韓語就希望全世界人跟著你學韓語。對於編程語言來說,打破兼容性還能平穩過渡的只有一種可能:這個語言沒幾個人在用……如何評價這個事兒:這是個好事兒,但這不是個大事兒。它可能給我們帶來一點兒困擾,但是2.7還在,你愛用哪個用哪個。近一段時間了解了C++, Erlang, Go, Java, Haskell, Scheme, Scala, Ruby, Python等語言之後,突然想明白一件兒事:其實語言不重要。編程語言很有用,但不重要。前兩天看到的一句話:「It is a lesson which all history teaches the wise, to put trust in ideas and not in circumstance.」,覺得用在取捨編程語言上也很有道理:不要信任(喜歡)那些語法的外衣,要對它們背後的想法保持信心!每一門語言背後都有獨特的想法。Python 2到Python 3語法變了,但The Zen of Python沒變,所以我依然挺它!我覺得2到3的不兼容只不過是The Zen of Python在Python演進中的反應,例如下面幾條:There should be one-- and preferably only one --obvious way to do it.If the implementation is easy to explain, it may be a good idea.作為個人,我現在老老實實用 2.7,瞄著 3.x,估計這種狀態可能會持續幾年. 不介意有些東西用用 3.x 寫,如果真的不需要什麼依賴的話.
想要兼容還是有辦法的,比如 https://pypi.python.org/pypi/six
至於拋棄後向兼容這種做法,似乎沒對我造成什麼影響(原因如上所述),這是應該的,改進了很多,反正自己水平太弱,寫的東西跑不了幾年,考慮那麼多兼容性幹嘛?順其自然吧……其實真的不用想太多,當年2.5上寫出的程序在2.4上跑不了也是常有的,加個大版本號,有些變化太正常了。比比perl5到perl6,python2to3簡直如絲般順滑。
其實嘛,我們都知道,設計protocol的時候一定要在數據裡面帶版本。其實如果語言也這樣的話……
fuck.py:
import python2 // 我們可以規定pythond+不能作為用戶自定義的模塊的名字
blahblahblah
shit.py:
import python3
import fuck
blahblahblah
然後允許混用,但是一個py只能用一個版本,而且低版本的文件看不見高版本的符號,輕鬆愉快。
一樓的說法不完全正確。有一個語言的演化過程里有打破兼容性,而且遷移的還算不錯,它是 Fortran。f90 規範里定義了一批「過時特性」(比如給老 IBM 機設計的 3 路 if),這些特性在 f95 里就給刪了,不過因為有 f90 到 f95 之間的「緩衝」,這項遷移並沒有造成很嚴重的問題。
Python 2還是有很多硬傷的。
不過是否應該打破向後兼容,這個真的很難說。
這種事情也取決於老大的性格,也許換個老大就不會這樣做。Python 3確實提高了非常多。也許幾年內會被向後兼容拖累,不過我覺得,十年後,大家也許會認同此時的決定。據我所知,沒有一個被廣泛使用的語言在打破向後兼容性的情況下依然得到平穩過渡。
如果喪失了向後兼容,本質上你就是一個新的不同的語言,那麼你自然無法完全的享受與遷移原有語言的資源。
C++ 語言的設計者最初的目的可是用來替代 C 的,可這麼多年過去了,他也只是成為了與 C 平行的一種語言而已,沒有辦法取代 C。——這個意思是說,無論開發者有多麼美好的願景,一個已經廣泛使用的語言很難被憑空廢棄,如果堅持 python3 這種不兼容策略,那麼後果將會是 python3 與 python2 發展成為兩種不同的平行發展的語言。總會有一個團體始終不理睬 python3
Lua 其實是版本不向後兼容的典型。但這裡有個問題,在 Lua 5.1 以前,Lua 並沒有得到非常廣泛的應用。Lua 大範圍應用其實是在 Lua 5.1 時代,而這個 5.1 時代延續了非常長的時間。
現在 Lua 5.2 出現了,打破了向後兼容,但是絕大多數使用者仍然使用的 Lua 5.1 語法。他向 5.2 的遷移可能會是個漫長的過程。而兄弟項目 LuaJIT 更是宣布在可以預見的將來永遠不會支持 5.2,一直堅持 5.1 語法的兼容性。這意味著 Lua 5.1 將在相當長的時間裡繼續存在為 Lua 的主流。而 5.2 成為了另外一種語言。
C 語言雖然這麼多年發展過不少標準,但是沒有打破過向後兼容性,非常老的代碼用今天的編譯器依然可以編譯(極端的情況可能需要一些編譯器選項)。這是一個非常典型的例證。
Python 打破向後兼容,當然純粹是開發者的好惡。不然你認為呢?我認為Python3打破向後兼容性的決定不是特別適當,至少不是特別經濟,作為一個以Python為編程母語,從2.5.4開始用Python寫代碼的程序員,我是不會 *主動* 切換到Python3的。這不是會不會或者能不能的問題,而是我完全沒有任何必要去為了不存在的利益付出哪怕一點點成本。我來具體分析一下Python3打破兼容性的幾個點:
- print從關鍵字變成內置函數,這個決定本身是正確的,print變成內置函數讓語言更加一致了,但是print是一個常用而不重要的功能,可以說大部分時候沒什麼功能性,主要是用來調試的,這個改變到底有什麼實質上的收益?我覺得是零。但是造成大量的Python2代碼被break,誰不會沒事print一下啊。這是個很昂貴而沒什麼收益的決定。
- 字元串字面量改成unicode字元串,Python3這方面的改進本質上只是把字元串字面量改成了unicode字元串,這個固然比原來默認byte string要好,但是你只要和外界交互----文件系統、網路、終端、GUI,你就必須理解byte string,結果還是要處理字符集和編碼問題,反過來,你不理解byte string和unicode string,用Python3照樣一頭霧水,從複雜性上講,Python2和Python3在字元串這個方面是相當的,Python3字面量是unicode要好一些,但是只要你理解字符集、編碼、unicode,byte string這幾個概念,Python2和Python3對你並無差別,在某些情況下,比如主要處理網路通信的情況下,字面量是byte string還要方便一些。
- dict.keys這類改動,從設計上講無疑是正確的,而且確實有性能改善,並且break的可能性其實並不大,因為你拿個dict.keys多半就是用來迭代的,拿來寫的可能性非常低,返回一個view其實沒什麼,但是既然有iterkeys這一類介面,那麼尊重現存代碼我覺得是更好的選擇,你這麼改只是好看一些,但是帶來了破壞的可能
總之,這些break的改動沒有帶來足夠的利益,但是造成的成本是很驚人的,不僅僅是改動幾處讓它能跑的問題,大量的第三方庫經過長時間的檢驗,已經證明了自己的功能性和穩定性,duang,沒有了,程序員和庫作者的穩定的預期被破壞了(要點不在於實際上出不出事,而是我為什麼要take這個risk)。
感覺 java 被拖累的一點就是歷史包袱有點厚重,缺少像 Python3 那樣有壯士斷腕的決心與魄力。
考慮到 python 的過去與將來,官方更注重未來,說明對將來的發展還是非常看好的。
這樣的話就不要說自己是一門語言
我只知道網上拷貝一段代碼 100%要去修改各種兼容性問題,在我學習的時候有一半以上的時間在解決這種兼容性的問題,如果不是工作需要,我個人絕對不會去學習這個語言
對於現在來看Python 2.7 和 Python 3 其實只是一些語法上面的差異而已, 但是可以看到, 現在已經有辦法可以保持他們的兼容的(雖然代碼果斷很難看 = = , 但畢竟是可以用的
而且 很多情況下, 比如說你服務端跑Python 2.X ,但是你客戶端跑Python 3 這個卻都是完全可以的。
目前來看, 大部分人估計是會保持使用Python 2.X 關注Python 3 的狀態, 在社區沒有完全過渡之前, 這個狀況會持續很長時間的可能作者覺得3.X前面的版本好多地方設計確實不合理或是影響效率,不如忍痛趕緊改掉。。。等到XXX版本後基本完全沒法改了吧。總的來說,作者還是為了以後的長遠發展考慮吧
我覺得都各執其詞,但是沒有人提到此決定的根本原因是什麼,是因為python本身的原理做不了向下兼容,還是因為雖然可以做,但是什麼其他原因。。。主要想知道原因
身為一個初學者,從網上拷貝個代碼下來學習,十之八九要去修改print。除此之外,還會有各種各樣包的不兼容性。太過靈活多變,沒有原則。極其不利於學習,不利於使用。我是真的想罵人。
當初golang沒成氣候的時候,就把py們迅速趕上3.x,停止維護2.7。
3.0有很多不錯的地方。
現在有很多轉go的了,雖然go相比py那必須是丑了很多,可是方便毋庸置疑。go本來號稱要殺java,一不小心把py給捅了一刀。樓主說的這些內容都比較有說服力,既然是設計失誤,修正過來總是好的。但今天下載了個python3.6試了一下,console里輸入exit()竟然告訴未定義???這是鬧的哪般?
3比2沒有本質性的性能提高(包括並發的支持),卻有本質性的語法不兼容,自然不受歡迎了
去掉print作為statement絕逼是個蠢決定,如果你要正經打log,自然有logger模塊用, print單單是不用帶括弧這個特性 已經足夠秒殺所有print語句。
推薦閱讀:
※如何評價南韓「圓佛教」?它還是佛教支流嗎?
※如何看待北京理工大學校團委副書記趙汐的言論?
※如何評價足利義昭?
※關於B站的某些雙標的問題各位怎麼看?
※如何評價《奇葩說》第二季每一位女神/男神的表現?