Python 2 和 Python 3 有哪些主要區別?


我來更正及評論下.

&> 1. print不再是語句,而是函數,比如原來是 print "abc" 現在是 print("abc")

但是 python2.6+ 可以使用 from __future__ import print_function 來實現相同功能

&> 2. 在Python 3中,沒有舊式類,只有新式類,也就是說不用再像這樣 class Foobar(object): pass 顯式地子類化object

但是最好還是加上. 主要區別在於 old-style 是 classtype 類型而 new-style 是 type類型

&> 3. 原來1/2(兩個整數相除)結果是0,現在是0.5了

python 2.2+ 以上都可以使用 from __future__ import division 實現改特性, 同時注意 // 取代了之前的 / 運算

&> 4. 新的字元串格式化方法format取代%

錯誤, 從 python2.6+ 開始已經在str和unicode中有該方法, 同時 python3依然支持 % 算符

&> 6. xrange重命名為range

同時更改的還有一系列內置函數及方法, 都返回迭代器對象, 而不是列表或者 元組, 比如 filter, map, dict.items 等

&> 7. !=取代 &< &>

python2 也很少有人用 &< &> 所以不算什麼修改

&> 8. long重命名為int

不完全對, python3 徹底廢棄了 long+int 雙整數實現的方法, 統一為 int , 支持高精度整數運算.

&> 9. except Exception, e變成except (Exception) as e

只有 python2.5 及以下版本不支持該語法. python2.6 是支持的. 不算新東西

&> 10. exec變成函數

類似 print() 的變化, 之前是語句.

簡單補充下

* 主要是類庫的變化, 組織結構變了些. 但功能沒變. urlparse - &> urllib.parse 這樣的變化

* 最核心的變化它沒有說, 對 bytes 和 原生 UNICODE 字元串的支持, 刪除了 unicode 對象, str 為原生 unicode 字元串, bytes 替代了之前的 str 這個是最核心的.

* 其它... 貌似不怎麼重要了.


print

在進行程序調試時用得最多的語句可能就是 print,在 Python 2 中,print 是一條語句,而 Python3 中作為函數存在。有人可能就有疑問了,我在 Python2 中明明也看到當函數使用:

# py2
print("hello") # 等價 print ("hello")

#py3
print("hello")

然而,你看到的只是表象,那麼上面兩個表達式有什麼區別?從輸出結果來看是一樣的,但本質上,前者是把 ("hello")當作一個整體,而後者 print()是個函數,接收字元串作為參數。

# py2
&>&>&> print("hello", "world")
("hello", "world")

# py3
&>&>&> print("hello", "world")
hello world

這個例子更明顯了,在 py2 中,print語句後面接的是一個元組對象,而在 py3 中,print 函數可以接收多個位置參數。如果希望在 Python2 中 把 print 當函數使用,那麼可以導入 future 模塊 中的 print_function

# py2
&>&>&> print("hello", "world")
("hello", "world")
&>&>&>
&>&>&> from __future__ import print_function
&>&>&> print("hello", "world")
hello world

編碼

Python2 的默認編碼是 asscii,這也是導致 Python2 中經常遇到編碼問題的原因之一,至於是為什麼會使用 asscii 作為默認編碼,原因在於 Python這門語言誕生的時候還沒出現 Unicode。Python 3 默認採用了 UTF-8 作為默認編碼,因此你不再需要在文件頂部寫 # coding=utf-8 了。

# py2
&>&>&> sys.getdefaultencoding()
"ascii"

# py3
&>&>&> sys.getdefaultencoding()
"utf-8"

網上不少文章說通過修改默認編碼格式來解決 Python2 的編碼問題,其實這是個大坑,不要這麼干。

字元串

字元串是最大的變化之一,這個變化使得編碼問題降到了最低可能。在 Python2 中,字元串有兩個類型,一個是 unicode,一個是 str,前者表示文本字元串,後者表示位元組序列,不過兩者並沒有明顯的界限,開發者也感覺很混亂,不明白編碼錯誤的原因,不過在 Python3 中兩者做了嚴格區分,分別用 str 表示字元串,byte 表示位元組序列,任何需要寫入文本或者網路傳輸的數據都只接收位元組序列,這就從源頭上阻止了編碼錯誤的問題。

True和False

True 和 False 在 Python2 中是兩個全局變數(名字),在數值上分別對應 1 和 0,既然是變數,那麼他們就可以指向其它對象,例如:

# py2
&>&>&> True = False
&>&>&> True
False
&>&>&> True is False
True
&>&>&> False = "x"
&>&>&> False
"x"
&>&>&> if False:
... print("?")
...
?

顯然,上面的代碼違背了 Python 的設計哲學 Explicit is better than implicit.。而 Python3 修正了這個缺陷,True 和 False 變為兩個關鍵字,永遠指向兩個固定的對象,不允許再被重新賦值。

# py3
&>&>&> True = 1
File "&", line 1
SyntaxError: can"t assign to keyword

迭代器

在 Python2 中很多返回列表對象的內置函數和方法在 Python 3 都改成了返回類似於迭代器的對象,因為迭代器的惰性載入特性使得操作大數據更有效率。Python2 中的 range 和 xrange 函數合併成了 range,如果同時兼容2和3,可以這樣:

try:
range = xrange
except:
pass

另外,字典對象的 dict.keys()、dict.values() 方法都不再返回列表,而是以一個類似迭代器的 "view" 對象返回。高階函數 map、filter、zip 返回的也都不是列表對象了。Python2的迭代器必須實現 next 方法,而 Python3 改成了 __next__

nonlocal

我們都知道在Python2中可以在函數裡面可以用關鍵字 global 聲明某個變數為全局變數,但是在嵌套函數中,想要給一個變數聲明為非局部變數是沒法實現的,在Pyhon3,新增了關鍵字 nonlcoal,使得非局部變數成為可能。

def func():
c = 1
def foo():
c = 12
foo()
print(c)
func() #1

可以對比上面兩段代碼的輸出結果

def func():
c = 1
def foo():
nonlocal c
c = 12
foo()
print(c)
func() # 12

其實很多內建模塊也做了大量調整,Python3 中的模塊組織更加清晰,類更加先進,還引入了非同步IO,先寫這麼多

-------更新-------

多謝知友 @YFdyh 指出,py2出現的時候其實已經有了unicode統一編碼了,只不過py2為了向後兼容還是沿用了py1.x的設計邏輯


按照當前時間點(Python 2.7 和 Python3.6),從宏觀上介紹下Python 3和Python 2的區別,並舉一些對應常見的例子:

1. 統一了字元編碼支持。我特意把它拿出來放在第一條...

2. 增加了新的語法。print/exec等成為了函數,格式化字元串變數,類型標註,添加了nonlocal、yield from、async/await、yield for關鍵詞和__annotations__、__context__、__traceback__、__qualname__等dunder方法。

3. 修改了一些語法。metaclass,raise、map、filter以及dict的items/keys/values方法返回迭代對象而不是列表,描述符協議,保存類屬性定義順序,保存關鍵字參數順序

4. 去掉了一些語法。cmp、&<&>(也就是!=)、xrange(其實就是range)、不再有經典類

5. 增加一些新的模塊。concurrent.futures、venv、unittest.mock、asyncio、selectors、typing等

6. 修改了一些模塊。主要是對模塊添加函數/類/方法(如functools.lru_cache、threading.Barrier)或者參數。

7. 模塊改名。把一些相關的模塊放進同一個包裡面(如httplib, BaseHTTPServer, CGIHTTPServer, SimpleHTTPServer, Cookie, cookielib放進了http裡面,urllib, urllib2, urlparse, robotparse放進了urllib裡面),個例如SocketServer改成了socketserver,Queue改成queue等

8. 去掉了一些模塊或者函數。gopherlib、md5、contextlib.nested、inspect.getmoduleinfo等。去掉的內容的原因主要是2點:1. 過時的技術產物,已經沒什麼人在用了;2. 出現了新的替代產物後者被證明存在意義不大。理論上對於開發者影響很小。

9. 優化。重新實現了dict可以減少20%-25%的內存使用;提升pickle序列化和反序列化的效率;collections.OrderedDict改用C實現;通過os.scandir對glob模塊中的glob()及iglob()進行優化,使得它們現在大概快了3-6倍等.. 這些都是喜大普奔的好消息,同樣開發者不需要感知,默默的就會讓結果變得更好。

10. 其他。構建過程、C的API、安全性等方面的修改,通常對於開發者不需要關心。

最後,重提一下我經常說的那句話:

Python 2/3的思想基本是共通的,只有少量的語法有差別甚至不兼容。當對Python熟悉到
一定程度時, 即使只會Python 2也可以在很短的時間就能寫Python 3的代碼。


RTFM.

這種事情直接在官網上看就可以了,沒必要提個問題。

另附鏈接:What』s New In Python 3.0


最主要的區別是 Python3 程序可以用中文寫

不過搞笑的是,有人說不太會看中文寫的程序(原話)。

我想他的意思應該是不太習慣,但仍然很搞笑。想知道他每天照鏡子時感覺是否習慣

要是有這麼一個變態公司/老闆,那就沒辦法了,拿人手短。


到這個題目大家可能猜到了我接下來要講些什麼,呵呵,對了,那就是列出這兩個不同版本間的卻別!

搜索一下大家就會知道,python有兩個主要的版本,python2 和 python3 ,但是python又不同於其他語言,向下兼容,python3是不向下兼容的,但是絕大多數組件和擴展都是基於python2的,下面就來總結一下python2和python3的區別。

1.性能

py3.0運行 pystone benchmark的速度比py2.5慢30%。guido認為py3.0有極大的優化空間,在字元串和整形操作上可以取得很好的優化結果。

py3.1性能比py2.5慢15%,還有很大的提升空間。

2.編碼

py3.x源碼文件默認使用utf-8編碼,這就使得以下代碼是合法的:

&>&>&> 中國 = "china"

&>&>&>print(中國)

china

3. 語法

1)去除了&<&>,全部改用!=

2)去除``,全部改用repr()

3)關鍵詞加入as 和with,還有true,false,none

4)整型除法返回浮點數,要得到整型結果,請使用//

5)加入nonlocal語句。使用noclocal x可以直接指派外圍(非全局)變數

6)去除print語句,加入print()函數實現相同的功能。同樣的還有 exec語句,已經改為exec()函數

例如:

2.x: print the answer is, 2*2

3.x: print(the answer is, 2*2)

2.x: print x, # 使用逗號結尾禁止換行

3.x: print(x, end= ) # 使用空格代替換行

2.x: print # 輸出新行

3.x: print() # 輸出新行

2.x: print &>&>sys.stderr, fatal error

3.x: print(fatal error, file=sys.stderr)

2.x: print (x, y) # 輸出repr((x, y))

3.x: print((x, y)) # 不同於print(x, y)!

7)改變了順序操作符的行為,例如x

8)輸入函數改變了,刪除了raw_input,用input代替:

2.x:guess = int(raw_input("enter an integer : ")) # 讀取鍵盤輸入的方法

3.x:guess = int(input("enter an integer : "))

9)去除元組參數解包。不能def(a, (b, c)):pass這樣定義函數了

10)新式的8進位字變數,相應地修改了oct()函數。

2.x的方式如下:

&>&>&> 0666

438

&>&>&> oct(438)

"0666"

3.x這樣:

&>&>&> 0666

syntaxerror: invalid token (

&>&>&> 0o666

438

&>&>&> oct(438)

"0o666"

11)增加了 2進位字面量和bin()函數

&>&>&> bin(438)

"0b110110110"

&>&>&> _438 = "0b110110110"

&>&>&> _438

"0b110110110"

12)擴展的可迭代解包。在py3.x 里,a, b, *rest = seq和 *rest, a = seq都是合法的,只要求兩點:rest是list

對象和seq是可迭代的。

13)新的super(),可以不再給super()傳參數,

&>&>&> class c(object):

def __init__(self, a):

print("c", a)

&>&>&> class d(c):

def __init(self, a):

super().__init__(a) # 無參數調用super()

&>&>&> d(8)

c 8

&<__main__.d object at 0x00d7ed90&>

還有:print不再是語句,而是函數,比如原來是 print "abc" 現在是 print("abc")但是 python2.6+ 可以使用 from __future__ import print_function 來實現相同功能&>; 在Python 3中,沒有舊式類,只有新式類,也就是說不用再像這樣 class Foobar(object): pass 顯式地子類化object但是最好還是加上。主要區別在於 old-style 是 classtype 類型而 new-style 是 type類型; 原來1/2(兩個整數相除)結果是0,現在是0.5了python 2.2+ 以上都可以使用 from __future__ import division 實現改特性,同時注意 // 取代了之前的 / 運算; 新的字元串格式化方法format取代%錯誤,從 python2.6+ 開始已經在str和unicode中有該方法, 同時 python3依然支持 % 算符; xrange重命名為range同時更改的還有一系列內置函數及方法, 都返回迭代器對象, 而不是列表或者 元組,比如 filter, map, dict.items 等; !=取代 &< &> python2 也很少有人用 &< &> 所以不算什麼修改; long重命名為int不完全對, python3 徹底廢棄了 long+int 雙整數實現的方法,統一為 int,支持高精度整數運算; except Exception,e變成except (Exception) as e只有 python2.5 及以下版本不支持該語法,python2.6 是支持的,不算新東西; exec變成函數類似 print() 的變化,之前是語句。

最後:現在信息更新的非常快速,又迎來了大數據的時代, 各行各業如果不與時俱進,都將面臨優勝劣汰,知識是不斷的更新的,只有一技之長,才能立於不敗之地。

學習Python編程語言,是大家走入編程世界的最理想選擇,在初期入門階段就可以自己動手做一些實用的小項目,這樣會極大的增進我們學習編程的 熱情。

很多朋友都是零基礎,沒有過編程的經驗或者一知半解,在選擇編程語言的時候面臨著眾多選擇,不知道哪種語言才是適合自己去深入學習的。 現在全世界大約有幾百萬以上的Python語言的用戶,大家可以看一下我在百度指數截圖的趨勢圖片,其實通過玩蛇網LEO多年學習和使用Python的經驗,發現大家選擇Python做為編程開發語言,主要有以下幾種原因:

首先,Python編寫代碼的速度非常的快,而且非常注重代碼的可讀性,非常適合多人參與的項目。它具備了比以前傳統的腳本語言更好的可重用性,維護起來也很方便。與現在流行的編程語言Java、C、C++等相比較,同樣是完成一個功能,Python編寫的代碼短小精幹,開發的效率是其它語言的好幾倍。

再者,Python支持多平台開發,用它編寫的代碼可以不經過任何轉換就能在Linux與Windows系統任何移植,在蘋果OS系統也沒有任何兼容性的問題. 不單單是你自己編寫的代碼具有可移植性,就連繫統提供的一些GUI圖形化編程、資料庫操作、網頁網路編程介面都可以耗不費力的移植到任何系統中。

還有,最重要的一點是Python有非常豐富的標準庫(Standard Library),標準庫連Python安裝程序已經直接安裝到你的系統當中去了,無需另外下載。 標準庫的這些模塊從字元串到網路腳本編程、遊戲開發、科學計算、資料庫介面等都給我們提供超級多的功能應用,不需要我們自己再去造輪子了。

哪些人適合學習Python?

1.編程菜鳥新手:非常喜愛編程,以後想從事相關工作,但是零基礎,不知道入門選擇什麼編程語言的朋友,其實是最適合選擇Python編程語言的。

2.網站前端的開發人員:平常只關注div+css這些頁面技術,很多時候其實需要與後端開發人員進行交互的;

3.一些工程師以前在做很多SEO優化的時候,苦於不會編程,一些程序上面的問題,得不到解決,只能做做簡單的頁面優化。 現在學會Python之後,你和我一樣都可以編寫一些查詢收錄,排名,自動生成網路地圖的程序,解決棘手的SEO問題,本站站長Leo有10年個人站長和SEO經驗,有興趣的朋友,互相交流一下。

4.在校學生:想有一技之長,或者是自學編程的愛好者,希望快速入門,少走彎路,都可以選擇Python語言。

5.Java程序員:現在有很多Java程序在轉到Python語言,他們都被Python代碼的優美和開發效率所折服,你還等什麼呢!

以上列舉了一些學習Python語言的原因和選擇的理由,當然還有更多的因素決定大家是否學習Python。

無論是學習任何一門語言,基礎知識,就是基礎功非常的重要,找一個有豐富編程經驗的老師或者師兄帶著你會少走很多彎路, 你的進步速度也會快很多,無論我們學習的目的是什麼,不得不說Python真的是一門值得你付出時間去學習的優秀編程
語言。

如果一門語言沒有改變你的編程思維,那麼它不值得你去學習」。如果這麼說,我們大學的時候,學習了c,c++,java,C#,算是值得學習么?很多時候是不值得,我覺得我們大學的課程就是用java,c#,c++把"C程序設計"又上了一遍.
這是因為,學校的老師會C和java之類的,所以要跟著規矩開這門課,(這也就是為什麼,許多學校還在教vb,),這也就是為什麼,你所以為的一樣就是大家都有For都有while,都有switch..都有Class...都有int 都有float,所謂的不一樣就是用C有指針,java沒有,這就是為什麼教育是失敗的,這也就是為什麼,我目前認識的幾個編程大牛
python的優點:簡單 我所說的簡單,是相比於象C和C++這樣的語言,你為了編程,要學習許多偏底層的東西.在比如,你在學習一個新的編程範式,或者想要馬上做個例子看看,試驗某個API,如果你是寫java的,你不得不去寫一個main,寫一些構造,即使有IDE這樣的東西,能夠為你帶來代碼生成器,而我做得就是寫一段「腳本」,或者打開python互動式解釋器就行了。
自己認識的python朋友出去工作,工資比較高,然後自己又剛剛好是會python所以選擇學習python,這樣的人比較危險但是也比較有激勵,還有就是覺得python比其他開發語言好用。

學完python前景會咋樣
其實我個人是很看好python未來的就業前景的,因為我認識太多的工程師都已經在學python,很多都是月收入大幾萬的
我個人也並非一直用python。前些年主要用c/c++以及java開發一些通信,移動系統,互聯網通信。近3年開始才轉向python。坦白的說,這可能與你相處的公司以及環境不大一樣。隨便舉個例子,google的protocol buffer協議一出來就具有c++/python/java三種語言支持。google的廣告系統早在03,04年左右就一併對python進行了webservice支持,大部分涉及基礎核心系統的公司,都開始對python進行了擴展支持。甚至開源社區的postgresql資料庫,除了自身的ansi SQL,pgsql,pg/TCL,PG/PERL之外對python進行了內嵌支持,唯獨卻沒有呼聲很高的java。在FREEBSD(MIT)/LINUX(GPL)平台上,對java可能排斥性比較大,但綜合而言,目前python發展還沒有java那種普及,主要是python大部分工作仍然是在較為深入地系統層和框架層做設計開發,例如django,SQLAlchemy,fail2ban,mail郵件系統,twisted等等。這部分對於那種習慣應用前輩們框架的編碼人員而言,缺乏創造力的他們根本無法適用這種開發。尤其在python涉及一些系統層面需要有較強的c/c++能力,這部分人在國內要麼就累得要死沒時間,要麼就啥都不會就會拷貝代碼,而國內公司也鮮有主動去做這部分基礎勞動的,大多都是等別人做好了在直接拿來用,所以造就了任何技術性的東西出來,國內都是先等等看,然後抄襲應用。
大環境如此,但千萬誤認為先等等看吧。對於一個技術人員而言,缺乏對新技術的渴望與熱情,這是一種非常危險的事情。我工作8年了,按照國內很多的人的說法早已不做代碼了,但又一次在聽一個老外的演講,他說他50多歲仍然每天堅持寫代碼,了解最新的動態,所以他才能做到他們公司的首席科學家,因此它才能時刻指導項目團隊前進並保證項目的質量。他坦言對於一個不寫代碼並且不了解最新的技術動態的技術人員或者技術團隊的負責人而言,這種團隊也就足夠做作小項目,一旦壓力和項目過大,就會有很多問題漏出來。
對於新人而言,無論學習什麼技術,都要以鼓勵的姿態出現。太多用薪水和你個人所看到的現狀去衡量一門技術,那絕對是欠缺眼光的。任何一門技術,一旦有人學習,他有可能逐漸成為這個領域的專家,即便再濫再沒有人用的開發語言技術,他也有可能就是明日的奠基者或者大師。

自己如何確定目標
在生活中學會不斷挖掘自己的潛力。我們都是一個普通人,可能並不清楚自己到底在哪方面佔有優勢。所以,學著在生活中找到自己的優勢,並根據優勢選擇一定的就業方向。
不隨波逐流。不要看周圍的人做什麼,自己就做什麼,也許別人做的並不適合你。別人的優勢很可能會成為你的劣勢。所以,堅定自己的想法,讓自己知道那些方面適合自己,自己可以勝任。
不斷嘗試可能成為自己的優勢。你不知道什麼適合自己,所以才要大膽、勇敢地嘗試。找到一種可以屬於你的獨特的優勢。
堅定信念。一旦你堅定了自己的信念,就不要被別人的意見或是諷刺或是嘲笑所干擾。別人不是你,不懂的你在想什麼,不清楚你開始這件事的源頭。你的事情,不了解你的人,沒有資格輕易評說。
不茫然,不多想。別讓太多的事干擾到你奮鬥下去的信念。夢想不容許太多的雜念。那些雜念只會讓你的心愈來愈脆弱,多為一個人考慮,到頭來,傷害的還是自己。

選擇自己學習方法
每個人都有適合自己的方法,有的人去選擇自學,有的人選擇看視頻學習,有的人選擇報名培訓班,那在這個時候,你就要自己考慮清楚,到底那樣對的幫助是最大的,個人覺得是跟著培訓班最好的,畢竟人家的實戰項目多,我們學軟體開發的都知道實戰項目對於學好一門語言是 很重要的。

學習python有那些誤區

具體裡面的誤區非常的多,那些就不需要我去寫出來,我給你說的一般都是心態的問題,首先一個覺得自己會java和c++,然後我學習python就很牛,但是你要知道語言是有很多相同的地方,但是不是通用,一定要自己學習的仔細。還有一種就是覺得我不會英語,我要先去把英語學習好在來學python。因為自己想還壞主意然後學習,這樣的都是容易找進誤區的。

怎麼樣才能學好python
學好python你需要一個良好的環境,一個優質的開發交流群,群里都是那種相互幫助的人才是可以的,我有建立一個python學習交流群,在群里我們相互幫助,相互關心,相互分享內容,這樣出問題幫助你的人就比較多,群號是304050799,這樣就可以找到大神聚合的群,如果你只願意別人幫助你,不願意分享或者幫助別人,那就請不要加了,你把你會的告訴別人這是一種分享。

感覺寫的好,對你有幫助,就點個讚唄,別光只收藏哈.~( ̄▽ ̄)~

?


幫樓上補一些

google "python 2 3 區別"

http://goo.gl/vs1ou


看到大家都沒說,我來補充個很重要的:

import在Python3中默認使用絕對路徑導入了,這是因為相對路徑的導入是具有歧義的

比如文件夾結構:

  • test/
    • main.py
    • lib/
      • __init__.py
      • some_func.py
      • other_func.py

如果運行的是main.py文件,python會將當前cwd作為PYTHONPATH變數

在main.py中,通過

import lib.some_func

或者

from lib import some_func

在some_func.py中,如果使用import other_func是會報錯的,建議使用

from lib import other_func

強行使用相對導入需要from .other_func import *

所以說從Python2遷移到Python3,會看到一個大型項目原有的代碼結構是否良好,如果之前你的代碼到處都是相對導入。。。嘖嘖

更詳細的參見:PEP 0328 -- Imports: Multi-Line and Absolute/Relative

詳細的2to3遷移事項可以參考2to3庫的文檔:26.6. 2to3 - Automated Python 2 to 3 code translation 能自動遷移的部分就不用人工了唄~

========分割線=====

時光的流逝,距離我上次改這個答案過去了兩年,最近完成了一個項目由Python2遷移至Python3,感悟還是那一個:好的代碼改起來真是舒適,我用了一下午的時間把我寫的新項目遷到了Python3。。不過我以前留在老東家的文檔我也沒有保存,這次只有新寫一個:

  1. 能被2to3遷移的都不用說
  2. 主要的痛點變成了bytes和str

bytes這個東西現在變得無處不在,所有進入系統的位元組流,包括並不限於各類系統讀例如os.urandom() 、各類網路IO

In [3]: import os

In [4]: os.urandom(10)
Out[4]: b"xc2/:x94xe1!x0cxabxe7e"

bytes和str的互操作,一些情況下會顯式失敗:

In [5]: _4+"asdasd"
TypeError: can"t concat bytes to str

一些情況是默認調用了bytes的__str__方法:

In [6]: "%s asdasd"%_4
Out[6]: "b"\xc2/:\x94\xe1!\x0c\xab\xe7e" asdasd"

後面這種靜默失敗比較危險,還好我在各個環節都寫了單元測試。。

另外很多以前接受str的函數,現在有兩種情況

1. 只接受bytes了,例如pickle.loads

2. 只接受str例如json.loads

但總的來說Unicode的麻煩比bytes大多了,所以遷到Python 3是合適的。但Unicode總體會降低少量CPU性能


Python 2.7.x 和 Python 3.x 的主要區別

  • 使用 __future__ 模塊
  • print 函數
  • Integer division
  • Unicode
  • xrange
  • Raising exceptions
  • Handling exceptions
  • next() 函數 和 .next() 方法
  • For 循環變數和全局命名空間泄漏
  • 比較不可排序類型
  • 通過 input() 解析用戶的輸入
  • 返回可迭代對象,而不是列表

原文地址為

Key differences between Python 2.7.x and Python 3.x

翻譯地址為

Python 2.7.x 和 Python 3.x 的主要區別修改


Python 2.7.x 與 Python 3.x 的主要差異,詳細介紹了Python 2 和Python 3 的差異,並在裡面貼了一些好文章,希望對你有幫助。


py3比py2更規範和統一一些,倒不是說py2不好,只不過因為歷史原因或一開始設計思路問題,變得有些複雜

print的改動,去掉了沒必要的關鍵字,換句話說能用函數的就用函數解決,輕量級語法+豐富的庫,不搞特化,exec和!=、&<&>也差不多基於同樣的思想(但是對於exec來說,有個問題需要確認,下面說)

int和long合併,新老類合併,跟上面一樣的原因,統一化,簡單說就是如果A能實現B全部的功能,或者B能從A簡單構造出來,則B沒必要存在了

range,map之類的返回迭代器也是基於同樣的理由,要實現py2的range,只需要list(range(...)),但反過來,py2要實現迭代器版本的,就只能增加一個xrange,而無法從range直接得到(range會消耗內存)

字元串改為unicode保存,新增位元組串,也是為了順應時代吧,這條貌似被褒獎得非常多,然而我還是要說,把編碼問題搞清楚最重要,搞不清楚的人用什麼都有可能出問題,只是概率大小的區別

最後說下exec的問題,因為我不用py3,沒深入研究,希望懂的人直接回復,不然我還得裝一個研究下。。

py作為動態語言,其作用域的變數的值可以大致看做是用{變數名:值}的形式存放在dict中,事實上global域就是這樣,不過函數局部變數比較特殊,是在編譯時就確定了數量的,所以可以用數組存放,比如

def f():

a = 1

b = 2

print a + b

其中a和b並不是做成{a:1,b:2}的形式,內部實現是一個數組,大致是[1,2]這樣(當然不是list,實際上CPython虛擬機是用一個類似Tuple的對象),然後存取都可以直接用偏移來做,這樣執行速度提升很明顯,因為絕大多數程序的絕大多數運算,都是在函數內部,這個情況在絕大多數語言中也都是成立的

但如果有exec就有問題了:

def f():

a = 1

exec "b = 2"

print a + b

這樣我們可以給局部變數域動態增減變數,編譯器無法感知,因為exec執行的字元串可能是動態生成的,編譯器無法感知,所以py2對這種情況的做法是,如果一個函數含有exec,則這個函數的局部變數域的訪問方式會和正常的函數不一樣,改為用類似global域的dict這種形式

所以這就要求編譯器感知到一個函數是否含有exec,因此exec作為語言關鍵字是必要的,如果作為函數,編譯器可能很難感知到了,因為py可以把函數賦值給其他名字的變數,或者給原本就有的函數名賦值一個其他函數


以下是我使用的python版本。

python2:

&>&>&> import sys
&>&>&> print sys.version
2.7.12+ (default, Sep 17 2016, 12:08:02)
[GCC 6.2.0 20160914]

python3:

&>&>&> import sys
&>&>&> print(sys.version)
3.5.2+ (default, Sep 22 2016, 12:18:14)
[GCC 6.2.0 20160927]

  • print變為了函數

Python2:

print "Hello, World!"

Hello, World!

Python3:

print "Hello, World!"

File "&", line 1
print "Hello, World!"
^
SyntaxError: Missing parentheses in call to "print"

print("Hello, World!")

Hello, World!

注意:給python2的print加括弧並不和python3等效,以下是反例。

python2:

print(1,2)

(1, 2)

python3:

print(1,2)

1 2

因為在python2里print不是函數,括弧內如果沒有逗號會被認為是數學表達式的括弧,忽略;如果有逗號,則會被認為是tuple。

  • raw_input重命名為input,覆蓋了原來的input函數,且raw_input這個函數名不再使用。

python2:

&>&>&> print type(input("Enter a number: "))
Enter a number: 3
&

&>&>&> print type(raw_input("Enter a number: "))
Enter a number: 3
&

python3:

&>&>&> print(type(input("Enter a number: ")))
Enter a number: 3
&

&>&>&> print(type(raw_input("Enter a number: ")))
Traceback (most recent call last):
File "&", line 1, in &
NameError: name "raw_input" is not defined

  • 整形除法自動轉為float

python2:

1/2
2/2
1//2

0

1

0

python3:

1/2
2/2
1//2

0.5

1.0

0

此外,long類型更名為int,覆蓋了int類型,long類型這個名稱不再使用。此外sys.maxint不存在了,因為現在int沒有最大值了。

  • 針對結尾是.5的小數,取整由四捨五入變為取最接近的偶數(銀行家舍入法)

python2:

round(1.5)
round(2.5)

2

3

python3:

round(1.5)
round(2.5)

2

2

  • 字元串統一用Unicode,並且增加了專門儲存位元組數據的類

python2:

print("u03BCnicou0394é!")

u03BCnicou0394é!

python3:

print("u03BCnicou0394é!")

μnicoΔé!

增加的兩個類是byte和bytearray,用來和字元串區分。

  • range跟xrange差不多了,因此xrange不存在了

python2:

type(range(5))
type(xrange(5))

&

&

python3:

type(range(5))

&

python3的range和原來的xrange還是有一點點區別的。

python2:

xrange(2**1000)

Traceback (most recent call last):
File "&", line 1, in &
OverflowError: Python int too large to convert to C long

python3:

range(2**1000)

range(0, 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376)

  • 跟print一樣,拋出異常也必須用括弧了

python2:

raise Exception, "for test"

Traceback (most recent call last):
File "&", line 1, in &
Exception: for test

python3:

raise Exception, "for test"

File "&", line 1
raise Exception, "for test"
^
SyntaxError: invalid syntax

raise Exception("for test")

Traceback (most recent call last):
File "&", line 1, in &
Exception: for test

  • 捕獲異常必須使用except...as...的格式

python2:

&>&>&> try:
... a = b
... except NameError, err:
... print "Something"s wrong!"
... print err
...
Something"s wrong!
name "b" is not defined

&>&>&> try:
... a = b
... except NameError as err:
... print "Something"s wrong!"
... print err
...
Something"s wrong!
name "b" is not defined

python3:

&>&>&> try:
... a = b
... except NameError, err:
File "&", line 3
except NameError, err:
^
SyntaxError: invalid syntax

&>&>&> try:
... a = b
... except NameError as err:
... print("Something"s wrong!")
... print(err)
...
Something"s wrong!
name "b" is not defined

編寫過程中主要參考了這篇文章:

The key differences between Python 2.7.x and Python 3.x with examples

另請參閱官方文檔中的比較:

https://docs.python.org/3/whatsnew/3.0.html


根據 Learn python the hard way 這本書的練習題,來區別 py2 和 py3。本人負基礎學 python,漫長的摸索階段啊……

### 1.修改 ex1.py

加上了 ()。

**發現:**print不再是語句,而是函數。python2.X 為 print "Hello world!" python3.X是 print("Hello world!")。

### 2.修改ex1.py,另存為ex101.py

**發現:** Py3.X源碼文件默認使用utf-8編碼,可以使用中文了。在Python3.X可以定義變數:漢字="test",print(漢字)而不會報錯,反過來也成立。

此外:給python2.X的print加括弧並不和python3.X等效,比如:

python2.X:

print(1,2)

(1, 2)

python3.X:

print(1,2)

1 2

查了下資料,說法如下:「因為在python2里print不是函數,括弧內如果沒有逗號會被認為是數學表達式的括弧,忽略;如果有逗號,則會被認為是tuple。」

### 3.修改 ex3.py

將以下:

print ("Is it true that 3 + 2 &< 5 - 7?")

print (3 + 2 &< 5 - 7)

print ("What is 3 + 2?", 3 + 2)

print ("What is 5 - 7?", 5 - 7)

print ("Oh,that"s why it"s False.")

修改為:

print ("Is it true that 3 / 2 &< 3 // 2 ?")

print ( 3 / 2 &< 3 // 2)

print ("What is 3 / 2 ?", 3 / 2)

print ("What is 3 // 2 ?", 3 // 2 )

print ("Oh,that"s why it"s False.")

**發現:**整形除法自動轉為float:在python 2.X里, 3 / 2 = 1, 3 // 2 = 1;而python 3.X里, 3 / 2 = 1.5, 3 // 2 = 1。

### 4.修改 ex11.py

**發現:** raw_input 在python 3.X 為

input,覆蓋了原來的input函數,不再使用raw_input這個函數名。

### 5.修改 ex4.py

**發現:** 是不是因為Unicode的原因,輸入(-2)**0.5 不會觸發錯誤,可以算出數值(但這個數值看起來很奇怪……) ,具體我還得再摸索一下。

最後,當然看官方文檔是最好的學習方式:[文檔](What』s New In Python 3.0)


我覺得比較給力得兩點

  1. 編碼問題
  2. async 協程加入


補充

類 ,在多繼承中搜索方式不一樣

python2中經典類和新式類,經典類搜索按深度優先,新式類按廣度優先。

python3中取消了經典類,還可以有新式類和經典類兩種寫法,但是都是廣度優先。

多繼承中,python2中新式類搜索父類__init__方法的方式為廣度優先,經典類為深度優先;

python3中默認為新式類,都使用廣度優先繼承,盡量使用新式類的寫法,括弧加上 object。

class A(object):

def __init__(self):

print("A")

class B(A):

def __init__(self):

print("B")

class C(A):

def __init__(self):

print("C")

class D(B,C):

#def __init__(self):

pass

d = D()

結果為:B

================================

將類B中的__init__注釋之後,結果為C

class A(object):

def __init__(self):

print("A")

class B(A):

# def __init__(self):

# print("B")

pass

class C(A):

def __init__(self):

print("C")

class D(B,C):

#def __init__(self):

pass

d = D()

列印C,使用廣度優先;(python2中的經典類會深度優先繼承A,列印A)


別說谷歌了,知乎上的人已經懶到連文檔都懶得看了。這種問題難道沒有官方文檔嗎?有什麼好答的?刷贊?


用一門語言無非是好用,其實用Python無關2.7Or3.6,用的好用稱手足矣。

現在有很多庫是基於2的,3不好用的時候嘗試下2,相反嘗試下3,總會找到自己的感覺。

區別樓上都說了,我也不再贅述。

本人拙見。


聯盟與部落


補充:urllib2已經被重構併入urllib模塊內部

為什麼 Python3 不能import urllib2

引用 https://docs.python.org/2/library/urllib2.html

Note

The urllib2 module has been split across several modules in Python 3 named urllib.request and urllib.error. The 2to3 tool will automatically adapt imports when converting your sources to Python 3.


1. print不再是語句,而是函數,比如原來是 print "abc" 現在是 print("abc")

2. 在Python 3中,沒有舊式類,只有新式類,也就是說不用再像這樣 class Foobar(object): pass 顯式地子類化object

3. 原來1/2(兩個整數相除)結果是0,現在是0.5了

4. 新的字元串格式化方法format取代%

5. raw_input重命名為input

6. xrange重命名為range

7. !=取代 &< &>

8. long重命名為int

9. except Exception, e變成except (Exception) as e

10. exec變成函數

其他還有很多。。。


推薦閱讀:

python exec in d 是往d中填充數據?
python作為腳本語言和c/c++ 等語言的優勢和劣勢在哪裡地方?python比較成熟用途在哪裡方面?
什麼樣的 Python 編輯器比較適合新手?
計算化學,有python基礎還有必要學習matlab么?

TAG:Python | A和B的比較 |