python3语法都相同吗_python2 与 python3 语法区别--转
原文地址:http://old.sebug.net/paper/books/dive-into-python3/porting-code-to-python-3-with-2to3.html
使用2to3將代碼移植到Python 3
? Life is pleasant. Death is peaceful. It’s the transition that’s troublesome. ?
— Isaac Asimov (attributed)
概述
幾乎所有的Python 2程序都需要一些修改才能正常地運(yùn)行在Python 3的環(huán)境下。為了簡(jiǎn)化這個(gè)轉(zhuǎn)換過(guò)程,Python 3自帶了一個(gè)叫做2to3的實(shí)用腳本(Utility Script),這個(gè)腳本會(huì)將你的Python 2程序源文件作為輸入,然后自動(dòng)將其轉(zhuǎn)換到Python 3的形式。案例研究:將chardet移植到Python 3(porting chardet to Python 3)描述了如何運(yùn)行這個(gè)腳本,然后展示了一些它不能自動(dòng)修復(fù)的情況。這篇附錄描述了它能夠自動(dòng)修復(fù)的內(nèi)容。
print語(yǔ)句
在Python 2里,print是一個(gè)語(yǔ)句。無(wú)論你想輸出什么,只要將它們放在print關(guān)鍵字后邊就可以。在Python 3里,print()是一個(gè)函數(shù)。就像其他的函數(shù)一樣,print()需要你將想要輸出的東西作為參數(shù)傳給它。
NotesPython 2Python 3
①
print()
②
print 1
print(1)
③
print 1, 2
print(1, 2)
④
print 1, 2,
print(1, 2, end=' ')
⑤
print >>sys.stderr, 1, 2, 3
print(1, 2, 3, file=sys.stderr)
為輸出一個(gè)空白行,需要調(diào)用不帶參數(shù)的print()。
為輸出一個(gè)單獨(dú)的值,需要將這這個(gè)值作為print()的一個(gè)參數(shù)就可以了。
為輸出使用一個(gè)空格分隔的兩個(gè)值,用兩個(gè)參數(shù)調(diào)用print()即可。
這個(gè)例子有一些技巧。在Python 2里,如果你使用一個(gè)逗號(hào)(,)作為print語(yǔ)句的結(jié)尾,它將會(huì)用空格分隔輸出的結(jié)果,然后在輸出一個(gè)尾隨的空格(trailing space),而不輸出回車(carriage return)。在Python 3里,通過(guò)把end=' '作為一個(gè)關(guān)鍵字參數(shù)傳給print()可以實(shí)現(xiàn)同樣的效果。參數(shù)end的默認(rèn)值為'\n',所以通過(guò)重新指定end參數(shù)的值,可以取消在末尾輸出回車符。
在Python 2里,你可以通過(guò)使用>>pipe_name語(yǔ)法,把輸出重定向到一個(gè)管道,比如sys.stderr。在Python 3里,你可以通過(guò)將管道作為關(guān)鍵字參數(shù)file的值傳遞給print()來(lái)完成同樣的功能。參數(shù)file的默認(rèn)值為std.stdout,所以重新指定它的值將會(huì)使print()輸出到一個(gè)另外一個(gè)管道。
Unicode字符串
Python 2有兩種字符串類型:Unicode字符串和非Unicode字符串。Python 3只有一種類型:Unicode字符串(Unicode strings)。
NotesPython 2Python 3
①
u'PapayaWhip'
'PapayaWhip'
②
ur'PapayaWhip\foo'
r'PapayaWhip\foo'
Python 2里的Unicode字符串在Python 3里即普通字符串,因?yàn)樵赑ython 3里字符串總是Unicode形式的。
Unicode原始字符串(raw string)(使用這種字符串,Python不會(huì)自動(dòng)轉(zhuǎn)義反斜線"\")也被替換為普通的字符串,因?yàn)樵赑ython 3里,所有原始字符串都是以Unicode編碼的。
全局函數(shù)unicode()
Python 2有兩個(gè)全局函數(shù)可以把對(duì)象強(qiáng)制轉(zhuǎn)換成字符串:unicode()把對(duì)象轉(zhuǎn)換成Unicode字符串,還有str()把對(duì)象轉(zhuǎn)換為非Unicode字符串。Python 3只有一種字符串類型,Unicode字符串,所以str()函數(shù)即可完成所有的功能。(unicode()函數(shù)在Python 3里不再存在了。)
NotesPython 2Python 3
unicode(anything)
str(anything)
long 長(zhǎng)整型
Python 2有為非浮點(diǎn)數(shù)準(zhǔn)備的int和long類型。int類型的最大值不能超過(guò)sys.maxint,而且這個(gè)最大值是平臺(tái)相關(guān)的。可以通過(guò)在數(shù)字的末尾附上一個(gè)L來(lái)定義長(zhǎng)整型,顯然,它比int類型表示的數(shù)字范圍更大。在Python 3里,只有一種整數(shù)類型int,大多數(shù)情況下,它很像Python 2里的長(zhǎng)整型。由于已經(jīng)不存在兩種類型的整數(shù),所以就沒有必要使用特殊的語(yǔ)法去區(qū)別他們。
NotesPython 2Python 3
①
x = 1000000000000L
x = 1000000000000
②
x = 0xFFFFFFFFFFFFL
x = 0xFFFFFFFFFFFF
③
long(x)
int(x)
④
type(x) is long
type(x) is int
⑤
isinstance(x, long)
isinstance(x, int)
在Python 2里的十進(jìn)制長(zhǎng)整型在Python 3里被替換為十進(jìn)制的普通整數(shù)。
在Python 2里的十六進(jìn)制長(zhǎng)整型在Python 3里被替換為十六進(jìn)制的普通整數(shù)。
在Python 3里,由于長(zhǎng)整型已經(jīng)不存在了,自然原來(lái)的long()函數(shù)也沒有了。為了強(qiáng)制轉(zhuǎn)換一個(gè)變量到整型,可以使用int()函數(shù)。
檢查一個(gè)變量是否是整型,獲得它的數(shù)據(jù)類型,并與一個(gè)int類型(不是long)的作比較。
你也可以使用isinstance()函數(shù)來(lái)檢查數(shù)據(jù)類型;再?gòu)?qiáng)調(diào)一次,使用int,而不是long,來(lái)檢查整數(shù)類型。
<> 比較運(yùn)算符
Python 2支持<>作為!=的同義詞。Python 3只支持!=,不再支持<>了。
NotesPython 2Python 3
①
if x <> y:
if x != y:
②
if x <> y <> z:
if x != y != z:
簡(jiǎn)單地比較。
相對(duì)復(fù)雜的三個(gè)值之間的比較。
字典類方法has_key()
在Python 2里,字典對(duì)象的has_key()方法用來(lái)測(cè)試字典是否包含特定的鍵(key)。Python 3不再支持這個(gè)方法了。你需要使用in運(yùn)算符。
NotesPython 2Python 3
①
a_dictionary.has_key('PapayaWhip')
'PapayaWhip' in a_dictionary
②
a_dictionary.has_key(x) or a_dictionary.has_key(y)
x in a_dictionary or y in a_dictionary
③
a_dictionary.has_key(x or y)
(x or y) in a_dictionary
④
a_dictionary.has_key(x + y)
(x + y) in a_dictionary
⑤
x + a_dictionary.has_key(y)
x + (y in a_dictionary)
最簡(jiǎn)單的形式。
運(yùn)算符or的優(yōu)先級(jí)高于運(yùn)算符in,所以這里不需要添加括號(hào)。
另一方面,出于同樣的原因 — or的優(yōu)先級(jí)大于in,這里需要添加括號(hào)。(注意:這里的代碼與前面那行完全不同。Python會(huì)先解釋x or y,得到結(jié)果x(如果x在布爾上下文里的值是真)或者y。然后Python檢查這個(gè)結(jié)果是不是a_dictionary的一個(gè)鍵。)
運(yùn)算符in的優(yōu)先級(jí)大于運(yùn)算符+,所以代碼里的這種形式從技術(shù)上說(shuō)不需要括號(hào),但是2to3還是添加了。
這種形式一定需要括號(hào),因?yàn)閕n的優(yōu)先級(jí)大于+。
返回列表的字典類方法
在Python 2里,許多字典類方法的返回值是列表。其中最常用方法的有keys,items和values。在Python 3里,所有以上方法的返回值改為動(dòng)態(tài)視圖(dynamic view)。在一些上下文環(huán)境里,這種改變并不會(huì)產(chǎn)生影響。如果這些方法的返回值被立即傳遞給另外一個(gè)函數(shù),并且那個(gè)函數(shù)會(huì)遍歷整個(gè)序列,那么以上方法的返回值是列表或者視圖并不會(huì)產(chǎn)生什么不同。在另外一些情況下,Python 3的這些改變干系重大。如果你期待一個(gè)能被獨(dú)立尋址元素的列表,那么Python 3的這些改變將會(huì)使你的代碼卡住(choke),因?yàn)橐晥D(view)不支持索引(indexing)。
NotesPython 2Python 3
①
a_dictionary.keys()
list(a_dictionary.keys())
②
a_dictionary.items()
list(a_dictionary.items())
③
a_dictionary.iterkeys()
iter(a_dictionary.keys())
④
[i for i in a_dictionary.iterkeys()]
[i for i in a_dictionary.keys()]
⑤
min(a_dictionary.keys())
no change
使用list()函數(shù)將keys()的返回值轉(zhuǎn)換為一個(gè)靜態(tài)列表,出于安全方面的考量,2to3可能會(huì)報(bào)錯(cuò)。這樣的代碼是有效的,但是對(duì)于使用視圖來(lái)說(shuō),它的效率低一些。你應(yīng)該檢查轉(zhuǎn)換后的代碼,看看是否一定需要列表,也許視圖也能完成同樣的工作。
這是另外一種視圖(關(guān)于items()方法的)到列表的轉(zhuǎn)換。2to3對(duì)values()方法返回值的轉(zhuǎn)換也是一樣的。
Python 3里不再支持iterkeys()了。如果必要,使用iter()將keys()的返回值轉(zhuǎn)換成為一個(gè)迭代器。
2to3能夠識(shí)別出iterkeys()方法在列表解析里被使用,然后將它轉(zhuǎn)換為Python 3里的keys()方法(不需要使用額外的iter()去包裝其返回值)。這樣是可行的,因?yàn)橐晥D是可迭代的。
2to3也能識(shí)別出keys()方法的返回值被立即傳給另外一個(gè)會(huì)遍歷整個(gè)序列的函數(shù),所以也就沒有必要先把keys()的返回值轉(zhuǎn)換到一個(gè)列表。相反的,min()函數(shù)會(huì)很樂(lè)意遍歷視圖。這個(gè)過(guò)程對(duì)min(),max(),sum(),list(),tuple(),set(),sorted(),any()和all()同樣有效。
被重命名或者重新組織的模塊
從Python 2到Python 3,標(biāo)準(zhǔn)庫(kù)里的一些模塊已經(jīng)被重命名了。還有一些相互關(guān)聯(lián)的模塊也被組合或者重新組織,以使得這種關(guān)聯(lián)更有邏輯性。
http
在Python 3里,幾個(gè)相關(guān)的HTTP模塊被組合成一個(gè)單獨(dú)的包,即http。
NotesPython 2Python 3
①
import httplib
import http.client
②
import Cookie
import http.cookies
③
import cookielib
import http.cookiejar
④
import BaseHTTPServer
import SimpleHTTPServer
import CGIHttpServer
import http.server
http.client模塊實(shí)現(xiàn)了一個(gè)底層的庫(kù),可以用來(lái)請(qǐng)求HTTP資源,解析HTTP響應(yīng)。
http.cookies模塊提供一個(gè)蟒樣的(Pythonic)接口來(lái)獲取通過(guò)HTTP頭部(HTTP header)Set-Cookie發(fā)送的cookies
常用的流行的瀏覽器會(huì)把cookies以文件形式存放在磁盤上,http.cookiejar模塊可以操作這些文件。
http.server模塊實(shí)現(xiàn)了一個(gè)基本的HTTP服務(wù)器
urllib
Python 2有一些用來(lái)分析,編碼和獲取URL的模塊,但是這些模塊就像老鼠窩一樣相互重疊。在Python 3里,這些模塊被重構(gòu)、組合成了一個(gè)單獨(dú)的包,即urllib。
NotesPython 2Python 3
①
import urllib
import urllib.request, urllib.parse, urllib.error
②
import urllib2
import urllib.request, urllib.error
③
import urlparse
import urllib.parse
④
import robotparser
import urllib.robotparser
⑤
from urllib import FancyURLopener
from urllib import urlencode
from urllib.request import FancyURLopener
from urllib.parse import urlencode
⑥
from urllib2 import Request
from urllib2 import HTTPError
from urllib.request import Request
from urllib.error import HTTPError
以前,Python 2里的urllib模塊有各種各樣的函數(shù),包括用來(lái)獲取數(shù)據(jù)的urlopen(),還有用來(lái)將URL分割成其組成部分的splittype(),splithost()和splituser()函數(shù)。在新的urllib包里,這些函數(shù)被組織得更有邏輯性。2to3將會(huì)修改這些函數(shù)的調(diào)用以適應(yīng)新的命名方案。
在Python 3里,以前的urllib2模塊被并入了urllib包。同時(shí),以u(píng)rllib2里各種你最喜愛的東西將會(huì)一個(gè)不缺地出現(xiàn)在Python 3的urllib模塊里,比如build_opener()方法,Request對(duì)象,HTTPBasicAuthHandler和friends。
Python 3里的urllib.parse模塊包含了原來(lái)Python 2里urlparse模塊所有的解析函數(shù)。
urllib.robotparse模塊解析robots.txt文件。
處理HTTP重定向和其他狀態(tài)碼的FancyURLopener類在Python 3里的urllib.request模塊里依然有效。urlencode()函數(shù)已經(jīng)被轉(zhuǎn)移到了urllib.parse里。
Request對(duì)象在urllib.request里依然有效,但是像HTTPError這樣的常量已經(jīng)被轉(zhuǎn)移到了urllib.error里。
我是否有提到2to3也會(huì)重寫你的函數(shù)調(diào)用?比如,如果你的Python 2代碼里導(dǎo)入了urllib模塊,調(diào)用了urllib.urlopen()函數(shù)獲取數(shù)據(jù),2to3會(huì)同時(shí)修改import語(yǔ)句和函數(shù)調(diào)用。
NotesPython 2Python 3
import urllib
print urllib.urlopen('http://diveintopython3.org/').read()
import urllib.request, urllib.parse, urllib.error
print(urllib.request.urlopen('http://diveintopython3.org/').read())
dbm
所有的DBM克隆(DBM clone)現(xiàn)在在單獨(dú)的一個(gè)包里,即dbm。如果你需要其中某個(gè)特定的變體,比如GNU DBM,你可以導(dǎo)入dbm包中合適的模塊。
NotesPython 2Python 3
import dbm
import dbm.ndbm
import gdbm
import dbm.gnu
import dbhash
import dbm.bsd
import dumbdbm
import dbm.dumb
import anydbm
import whichdb
import dbm
xmlrpc
XML-RPC是一個(gè)通過(guò)HTTP協(xié)議執(zhí)行遠(yuǎn)程RPC調(diào)用的輕重級(jí)方法。一些XML-RPC客戶端和XML-RPC服務(wù)端的實(shí)現(xiàn)庫(kù)現(xiàn)在被組合到了獨(dú)立的包,即xmlrpc。
NotesPython 2Python 3
import xmlrpclib
import xmlrpc.client
import DocXMLRPCServer
import SimpleXMLRPCServer
import xmlrpc.server
其他模塊
NotesPython 2Python 3
①
try:
import cStringIO as StringIO
except ImportError:
import StringIO
import io
②
try:
import cPickle as pickle
except ImportError:
import pickle
import pickle
③
import __builtin__
import builtins
④
import copy_reg
import copyreg
⑤
import Queue
import queue
⑥
import SocketServer
import socketserver
⑦
import ConfigParser
import configparser
⑧
import repr
import reprlib
⑨
import commands
import subprocess
在Python 2里,你通常會(huì)這樣做,首先嘗試把cStringIO導(dǎo)入作為StringIO的替代,如果失敗了,再導(dǎo)入StringIO。不要在Python 3里這樣做;io模塊會(huì)幫你處理好這件事情。它會(huì)找出可用的最快實(shí)現(xiàn)方法,然后自動(dòng)使用它。
在Python 2里,導(dǎo)入最快的pickle實(shí)現(xiàn)也是一個(gè)與上邊相似的能用方法。在Python 3里,pickle模塊會(huì)自動(dòng)為你處理,所以不要再這樣做。
builtins模塊包含了在整個(gè)Python語(yǔ)言里都會(huì)使用的全局函數(shù),類和常量。重新定義builtins模塊里的某個(gè)函數(shù)意味著在每處都重定義了這個(gè)全局函數(shù)。這聽起來(lái)很強(qiáng)大,但是同時(shí)也是很可怕的。
copyreg模塊為用C語(yǔ)言定義的用戶自定義類型添加了pickle模塊的支持。
queue模塊實(shí)現(xiàn)一個(gè)生產(chǎn)者消費(fèi)者隊(duì)列(multi-producer, multi-consumer queue)。
socketserver模塊為實(shí)現(xiàn)各種socket server提供了通用基礎(chǔ)類。
configparser模塊用來(lái)解析INI-style配置文件。
reprlib模塊重新實(shí)現(xiàn)了內(nèi)置函數(shù)repr(),并添加了對(duì)字符串表示被截?cái)嗲伴L(zhǎng)度的控制。
subprocess模塊允許你創(chuàng)建子進(jìn)程,連接到他們的管道,然后獲取他們的返回值。
包內(nèi)的相對(duì)導(dǎo)入
包是由一組相關(guān)聯(lián)的模塊共同組成的單個(gè)實(shí)體。在Python 2的時(shí)候,為了實(shí)現(xiàn)同一個(gè)包內(nèi)模塊的相互引用,你會(huì)使用import foo或者from foo import Bar。Python 2解釋器會(huì)先在當(dāng)前目錄里搜索foo.py,然后再去Python搜索路徑(sys.path)里搜索。在Python 3里這個(gè)過(guò)程有一點(diǎn)不同。Python 3不會(huì)首先在當(dāng)前路徑搜索,它會(huì)直接在Python的搜索路徑里尋找。如果你想要包里的一個(gè)模塊導(dǎo)入包里的另外一個(gè)模塊,你需要顯式地提供兩個(gè)模塊的相對(duì)路徑。
假設(shè)你有如下包,多個(gè)文件在同一個(gè)目錄下:
chardet/
|
+--__init__.py
|
+--constants.py
|
+--mbcharsetprober.py
|
+--universaldetector.py
現(xiàn)在假設(shè)universaldetector.py需要整個(gè)導(dǎo)入constants.py,另外還需要導(dǎo)入mbcharsetprober.py的一個(gè)類。你會(huì)怎樣做?
NotesPython 2Python 3
①
import constants
from . import constants
②
from mbcharsetprober import MultiByteCharSetProber
from .mbcharsetprober import MultiByteCharsetProber
當(dāng)你需要從包的其他地方導(dǎo)入整個(gè)模塊,使用新的from . import語(yǔ)法。這里的句號(hào)(.)即表示當(dāng)前文件(universaldetector.py)和你想要導(dǎo)入文件(constants.py)之間的相對(duì)路徑。在這個(gè)樣例中,這兩個(gè)文件在同一個(gè)目錄里,所以使用了單個(gè)句號(hào)。你也可以從父目錄(from .. import anothermodule)或者子目錄里導(dǎo)入。
為了將一個(gè)特定的類或者函數(shù)從其他模塊里直接導(dǎo)入到你的模塊的名字空間里,在需要導(dǎo)入的模塊名前加上相對(duì)路徑,并且去掉最后一個(gè)斜線(slash)。在這個(gè)例子中,mbcharsetprober.py與universaldetector.py在同一個(gè)目錄里,所以相對(duì)路徑名就是一個(gè)句號(hào)。你也可以從父目錄(from .. import anothermodule)或者子目錄里導(dǎo)入。
迭代器方法next()
在Python 2里,迭代器有一個(gè)next()方法,用來(lái)返回序列里的下一項(xiàng)。在Python 3里這同樣成立,但是現(xiàn)在有了一個(gè)新的全局的函數(shù)next(),它使用一個(gè)迭代器作為參數(shù)。
NotesPython 2Python 3
①
anIterator.next()
next(anIterator)
②
a_function_that_returns_an_iterator().next()
next(a_function_that_returns_an_iterator())
③
class A:
def next(self):
pass
class A:
def __next__(self):
pass
④
class A:
def next(self, x, y):
pass
no change
⑤
next = 42
for an_iterator in a_sequence_of_iterators:
an_iterator.next()
next = 42
for an_iterator in a_sequence_of_iterators:
an_iterator.__next__()
最簡(jiǎn)單的例子,你不再調(diào)用一個(gè)迭代器的next()方法,現(xiàn)在你將迭代器自身作為參數(shù)傳遞給全局函數(shù)next()。
假如你有一個(gè)返回值是迭代器的函數(shù),調(diào)用這個(gè)函數(shù)然后把結(jié)果作為參數(shù)傳遞給next()函數(shù)。(2to3腳本足夠智能以正確執(zhí)行這種轉(zhuǎn)換。)
假如你想定義你自己的類,然后把它用作一個(gè)迭代器,在Python 3里,你可以通過(guò)定義特殊方法__next__()來(lái)實(shí)現(xiàn)。
如果你定義的類里剛好有一個(gè)next(),它使用一個(gè)或者多個(gè)參數(shù),2to3執(zhí)行的時(shí)候不會(huì)動(dòng)它。這個(gè)類不能被當(dāng)作迭代器使用,因?yàn)樗膎ext()方法帶有參數(shù)。
這一個(gè)有些復(fù)雜。如果你恰好有一個(gè)叫做next的本地變量,在Python 3里它的優(yōu)先級(jí)會(huì)高于全局函數(shù)next()。在這種情況下,你需要調(diào)用迭代器的特別方法__next__()來(lái)獲取序列里的下一個(gè)元素。(或者,你也可以重構(gòu)代碼以使這個(gè)本地變量的名字不叫next,但是2to3不會(huì)為你做這件事。)
全局函數(shù)filter()
在Python 2里,filter()方法返回一個(gè)列表,這個(gè)列表是通過(guò)一個(gè)返回值為True或者False的函數(shù)來(lái)檢測(cè)序列里的每一項(xiàng)得到的。在Python 3里,filter()函數(shù)返回一個(gè)迭代器,不再是列表。
NotesPython 2Python 3
①
filter(a_function, a_sequence)
list(filter(a_function, a_sequence))
②
list(filter(a_function, a_sequence))
no change
③
filter(None, a_sequence)
[i for i in a_sequence if i]
④
for i in filter(None, a_sequence):
no change
⑤
[i for i in filter(a_function, a_sequence)]
no change
最簡(jiǎn)單的情況下,2to3會(huì)用一個(gè)list()函數(shù)來(lái)包裝filter(),list()函數(shù)會(huì)遍歷它的參數(shù)然后返回一個(gè)列表。
然而,如果filter()調(diào)用已經(jīng)被list()包裹,2to3不會(huì)再做處理,因?yàn)檫@種情況下filter()的返回值是否是一個(gè)迭代器是無(wú)關(guān)緊要的。
為了處理filter(None, ...)這種特殊的語(yǔ)法,2to3會(huì)將這種調(diào)用從語(yǔ)法上等價(jià)地轉(zhuǎn)換為列表解析。
由于for循環(huán)會(huì)遍歷整個(gè)序列,所以沒有必要再做修改。
與上面相同,不需要做修改,因?yàn)榱斜斫馕鰰?huì)遍歷整個(gè)序列,即使filter()返回一個(gè)迭代器,它仍能像以前的filter()返回列表那樣正常工作。
全局函數(shù)map()
跟filter()作的改變一樣,map()函數(shù)現(xiàn)在返回一個(gè)迭代器。(在Python 2里,它返回一個(gè)列表。)
NotesPython 2Python 3
①
map(a_function, 'PapayaWhip')
list(map(a_function, 'PapayaWhip'))
②
map(None, 'PapayaWhip')
list('PapayaWhip')
③
map(lambda x: x+1, range(42))
[x+1 for x in range(42)]
④
for i in map(a_function, a_sequence):
no change
⑤
[i for i in map(a_function, a_sequence)]
no change
類似對(duì)filter()的處理,在最簡(jiǎn)單的情況下,2to3會(huì)用一個(gè)list()函數(shù)來(lái)包裝map()調(diào)用。
對(duì)于特殊的map(None, ...)語(yǔ)法,跟filter(None, ...)類似,2to3會(huì)將其轉(zhuǎn)換成一個(gè)使用list()的等價(jià)調(diào)用
如果map()的第一個(gè)參數(shù)是一個(gè)lambda函數(shù),2to3會(huì)將其等價(jià)地轉(zhuǎn)換成列表解析。
對(duì)于會(huì)遍歷整個(gè)序列的for循環(huán),不需要做改變。
再一次地,這里不需要做修改,因?yàn)榱斜斫馕鰰?huì)遍歷整個(gè)序列,即使map()的返回值是迭代器而不是列表它也能正常工作。
全局函數(shù)reduce()
在Python 3里,reduce()函數(shù)已經(jīng)被從全局名字空間里移除了,它現(xiàn)在被放置在fucntools模塊里。
NotesPython 2Python 3
reduce(a, b, c)
from functools import reduce
reduce(a, b, c)
全局函數(shù)apply()
Python 2有一個(gè)叫做apply()的全局函數(shù),它使用一個(gè)函數(shù)f和一個(gè)列表[a, b, c]作為參數(shù),返回值是f(a, b, c)。你也可以通過(guò)直接調(diào)用這個(gè)函數(shù),在列表前添加一個(gè)星號(hào)(*)作為參數(shù)傳遞給它來(lái)完成同樣的事情。在Python 3里,apply()函數(shù)不再存在了;必須使用星號(hào)標(biāo)記法。
NotesPython 2Python 3
①
apply(a_function, a_list_of_args)
a_function(*a_list_of_args)
②
apply(a_function, a_list_of_args, a_dictionary_of_named_args)
a_function(*a_list_of_args, **a_dictionary_of_named_args)
③
apply(a_function, a_list_of_args + z)
a_function(*a_list_of_args + z)
④
apply(aModule.a_function, a_list_of_args)
aModule.a_function(*a_list_of_args)
最簡(jiǎn)單的形式,可以通過(guò)在參數(shù)列表(就像[a, b, c]一樣)前添加一個(gè)星號(hào)來(lái)調(diào)用函數(shù)。這跟Python 2里的apply()函數(shù)是等價(jià)的。
在Python 2里,apply()函數(shù)實(shí)際上可以帶3個(gè)參數(shù):一個(gè)函數(shù),一個(gè)參數(shù)列表,一個(gè)字典命名參數(shù)(dictionary of named arguments)。在Python 3里,你可以通過(guò)在參數(shù)列表前添加一個(gè)星號(hào)(*),在字典命名參數(shù)前添加兩個(gè)星號(hào)(**)來(lái)達(dá)到同樣的效果。
運(yùn)算符+在這里用作連接列表的功能,它的優(yōu)先級(jí)高于運(yùn)算符*,所以沒有必要在a_list_of_args + z周圍添加額外的括號(hào)。
2to3腳本足夠智能來(lái)轉(zhuǎn)換復(fù)雜的apply()調(diào)用,包括調(diào)用導(dǎo)入模塊里的函數(shù)。
全局函數(shù)intern()
在Python 2里,你可以用intern()函數(shù)作用在一個(gè)字符串上來(lái)限定(intern)它以達(dá)到性能優(yōu)化。在Python 3里,intern()函數(shù)被轉(zhuǎn)移到sys模塊里了。
NotesPython 2Python 3
intern(aString)
sys.intern(aString)
exec語(yǔ)句
就像print語(yǔ)句在Python 3里變成了一個(gè)函數(shù)一樣,exec語(yǔ)句也是這樣的。exec()函數(shù)使用一個(gè)包含任意Python代碼的字符串作為參數(shù),然后就像執(zhí)行語(yǔ)句或者表達(dá)式一樣執(zhí)行它。exec()跟eval()是相似的,但是exec()更加強(qiáng)大并更具有技巧性。eval()函數(shù)只能執(zhí)行單獨(dú)一條表達(dá)式,但是exec()能夠執(zhí)行多條語(yǔ)句,導(dǎo)入(import),函數(shù)聲明 — 實(shí)際上整個(gè)Python程序的字符串表示也可以。
NotesPython 2Python 3
①
exec codeString
exec(codeString)
②
exec codeString in a_global_namespace
exec(codeString, a_global_namespace)
③
exec codeString in a_global_namespace, a_local_namespace
exec(codeString, a_global_namespace, a_local_namespace)
在最簡(jiǎn)單的形式下,因?yàn)閑xec()現(xiàn)在是一個(gè)函數(shù),而不是語(yǔ)句,2to3會(huì)把這個(gè)字符串形式的代碼用括號(hào)圍起來(lái)。
Python 2里的exec語(yǔ)句可以指定名字空間,代碼將在這個(gè)由全局對(duì)象組成的私有空間里執(zhí)行。Python 3也有這樣的功能;你只需要把這個(gè)名字空間作為第二個(gè)參數(shù)傳遞給exec()函數(shù)。
更加神奇的是,Python 2里的exec語(yǔ)句還可以指定一個(gè)本地名字空間(比如一個(gè)函數(shù)里聲明的變量)。在Python 3里,exec()函數(shù)也有這樣的功能。
execfile語(yǔ)句
就像以前的exec語(yǔ)句,Python 2里的execfile語(yǔ)句也可以像執(zhí)行Python代碼那樣使用字符串。不同的是exec使用字符串,而execfile則使用文件。在Python 3里,execfile語(yǔ)句已經(jīng)被去掉了。如果你真的想要執(zhí)行一個(gè)文件里的Python代碼(但是你不想導(dǎo)入它),你可以通過(guò)打開這個(gè)文件,讀取它的內(nèi)容,然后調(diào)用compile()全局函數(shù)強(qiáng)制Python解釋器編譯代碼,然后調(diào)用新的exec()函數(shù)。
NotesPython 2Python 3
execfile('a_filename')
exec(compile(open('a_filename').read(), 'a_filename', 'exec'))
repr(反引號(hào))
在Python 2里,為了得到一個(gè)任意對(duì)象的字符串表示,有一種把對(duì)象包裝在反引號(hào)里(比如`x`)的特殊語(yǔ)法。在Python 3里,這種能力仍然存在,但是你不能再使用反引號(hào)獲得這種字符串表示了。你需要使用全局函數(shù)repr()。
NotesPython 2Python 3
①
`x`
repr(x)
②
`'PapayaWhip' + `2``
repr('PapayaWhip' + repr(2))
記住,x可以是任何東西 — 一個(gè)類,函數(shù),模塊,基本數(shù)據(jù)類型,等等。repr()函數(shù)可以使用任何類型的參數(shù)。
在Python 2里,反引號(hào)可以嵌套,導(dǎo)致了這種令人費(fèi)解的(但是有效的)表達(dá)式。2to3足夠智能以將這種嵌套調(diào)用轉(zhuǎn)換到repr()函數(shù)。
try...except語(yǔ)句
從Python 2到Python 3,捕獲異常的語(yǔ)法有些許變化。
NotesPython 2Python 3
①
try:
import mymodule
except ImportError, e
pass
try:
import mymodule
except ImportError as e:
pass
②
try:
import mymodule
except (RuntimeError, ImportError), e
pass
try:
import mymodule
except (RuntimeError, ImportError) as e:
pass
③
try:
import mymodule
except ImportError:
pass
no change
④
try:
import mymodule
except:
pass
no change
相對(duì)于Python 2里在異常類型后添加逗號(hào),Python 3使用了一個(gè)新的關(guān)鍵字,as。
關(guān)鍵字as也可以用在一次捕獲多種類型異常的情況下。
如果你捕獲到一個(gè)異常,但是并不在意訪問(wèn)異常對(duì)象本身,Python 2和Python 3的語(yǔ)法是一樣的。
類似地,如果你使用一個(gè)保險(xiǎn)方法(fallback)來(lái)捕獲所有異常,Python 2和Python 3的語(yǔ)法是一樣的。
?在導(dǎo)入模塊(或者其他大多數(shù)情況)的時(shí)候,你絕對(duì)不應(yīng)該使用這種方法(指以上的fallback)。不然的話,程序可能會(huì)捕獲到像KeyboardInterrupt(如果用戶按Ctrl-C來(lái)中斷程序)這樣的異常,從而使調(diào)試變得更加困難。
raise語(yǔ)句
Python 3里,拋出自定義異常的語(yǔ)法有細(xì)微的變化。
NotesPython 2Python 3
①
raise MyException
unchanged
②
raise MyException, 'error message'
raise MyException('error message')
③
raise MyException, 'error message', a_traceback
raise MyException('error message').with_traceback(a_traceback)
④
raise 'error message'
unsupported
拋出不帶用戶自定義錯(cuò)誤信息的異常,這種最簡(jiǎn)單的形式下,語(yǔ)法沒有改變。
當(dāng)你想要拋出一個(gè)帶用戶自定義錯(cuò)誤信息的異常時(shí),改變就顯而易見了。Python 2用一個(gè)逗號(hào)來(lái)分隔異常類和錯(cuò)誤信息;Python 3把錯(cuò)誤信息作為參數(shù)傳遞給異常類。
Python 2支持一種更加復(fù)雜的語(yǔ)法來(lái)拋出一個(gè)帶用戶自定義回溯(stack trace,堆棧追蹤)的異常。在Python 3里你也可以這樣做,但是語(yǔ)法完全不同。
在Python 2里,你可以拋出一個(gè)不帶異常類的異常,僅僅只有一個(gè)異常信息。在Python 3里,這種形式不再被支持。2to3將會(huì)警告你它不能自動(dòng)修復(fù)這種語(yǔ)法。
生成器的throw方法
在Python 2里,生成器有一個(gè)throw()方法。調(diào)用a_generator.throw()會(huì)在生成器被暫停的時(shí)候拋出一個(gè)異常,然后返回由生成器函數(shù)獲取的下一個(gè)值。在Python 3里,這種功能仍然可用,但是語(yǔ)法上有一點(diǎn)不同。
NotesPython 2Python 3
①
a_generator.throw(MyException)
no change
②
a_generator.throw(MyException, 'error message')
a_generator.throw(MyException('error message'))
③
a_generator.throw('error message')
unsupported
最簡(jiǎn)單的形式下,生成器拋出不帶用戶自定義錯(cuò)誤信息的異常。這種情況下,從Python 2到Python 3語(yǔ)法上沒有變化 。
如果生成器拋出一個(gè)帶用戶自定義錯(cuò)誤信息的異常,你需要將這個(gè)錯(cuò)誤信息字符串(error string)傳遞給異常類來(lái)以實(shí)例化它。
Python 2還支持拋出只有異常信息的異常。Python 3不支持這種語(yǔ)法,并且2to3會(huì)顯示一個(gè)警告信息,告訴你需要手動(dòng)地來(lái)修復(fù)這處代碼。
全局函數(shù)xrange()
在Python 2里,有兩種方法來(lái)獲得一定范圍內(nèi)的數(shù)字:range(),它返回一個(gè)列表,還有range(),它返回一個(gè)迭代器。在Python 3里,range()返回迭代器,xrange()不再存在了。
NotesPython 2Python 3
①
xrange(10)
range(10)
②
a_list = range(10)
a_list = list(range(10))
③
[i for i in xrange(10)]
[i for i in range(10)]
④
for i in range(10):
no change
⑤
sum(range(10))
no change
在最簡(jiǎn)單的情況下,2to3會(huì)簡(jiǎn)單地把xrange()轉(zhuǎn)換為range()。
如果你的Python 2代碼使用range(),2to3不知道你是否需要一個(gè)列表,或者是否一個(gè)迭代器也行。出于謹(jǐn)慎,2to3可能會(huì)報(bào)錯(cuò),然后使用list()把range()的返回值強(qiáng)制轉(zhuǎn)換為列表類型。
如果在列表解析里有xrange()函數(shù),就沒有必要將其返回值轉(zhuǎn)換為一個(gè)列表,因?yàn)榱斜斫馕鰧?duì)迭代器同樣有效。
類似的,for循環(huán)也能作用于迭代器,所以這里也沒有改變?nèi)魏螙|西。
函數(shù)sum()能作用于迭代器,所以2to3也沒有在這里做出修改。就像返回值為視圖(view)而不再是列表的字典類方法一樣,這同樣適用于min(),max(),sum(),list(),tuple(),set(),sorted(),any(),all()。
全局函數(shù)raw_input()和input()
Python 2有兩個(gè)全局函數(shù),用來(lái)在命令行請(qǐng)求用戶輸入。第一個(gè)叫做input(),它等待用戶輸入一個(gè)Python表達(dá)式(然后返回結(jié)果)。第二個(gè)叫做raw_input(),用戶輸入什么它就返回什么。這讓初學(xué)者非常困惑,并且這被廣泛地看作是Python語(yǔ)言的一個(gè)“肉贅”(wart)。Python 3通過(guò)重命名raw_input()為input(),從而切掉了這個(gè)肉贅,所以現(xiàn)在的input()就像每個(gè)人最初期待的那樣工作。
NotesPython 2Python 3
①
raw_input()
input()
②
raw_input('prompt')
input('prompt')
③
input()
eval(input())
最簡(jiǎn)單的形式,raw_input()被替換成input()。
在Python 2里,raw_input()函數(shù)可以指定一個(gè)提示符作為參數(shù)。Python 3里保留了這個(gè)功能。
如果你真的想要請(qǐng)求用戶輸入一個(gè)Python表達(dá)式,計(jì)算結(jié)果,可以通過(guò)調(diào)用input()函數(shù)然后把返回值傳遞給eval()。
函數(shù)屬性func_*
在Python 2里,函數(shù)的里的代碼可以訪問(wèn)到函數(shù)本身的特殊屬性。在Python 3里,為了一致性,這些特殊屬性被重新命名了。
NotesPython 2Python 3
①
a_function.func_name
a_function.__name__
②
a_function.func_doc
a_function.__doc__
③
a_function.func_defaults
a_function.__defaults__
④
a_function.func_dict
a_function.__dict__
⑤
a_function.func_closure
a_function.__closure__
⑥
a_function.func_globals
a_function.__globals__
⑦
a_function.func_code
a_function.__code__
__name__屬性(原func_name)包含了函數(shù)的名字。
__doc__屬性(原funcdoc)包含了你在函數(shù)源代碼里定義的文檔字符串(docstring)
__defaults__屬性(原func_defaults)是一個(gè)保存參數(shù)默認(rèn)值的元組。
__dict__屬性(原func_dict)是一個(gè)支持任意函數(shù)屬性的名字空間。
__closure__屬性(原func_closure)是一個(gè)由cell對(duì)象組成的元組,它包含了函數(shù)對(duì)自由變量(free variable)的綁定。
__globals__屬性(原func_globals)是一個(gè)對(duì)模塊全局名字空間的引用,函數(shù)本身在這個(gè)名字空間里被定義。
__code__屬性(原func_code)是一個(gè)代碼對(duì)象,表示編譯后的函數(shù)體。
I/O方法xreadlines()
在Python 2里,文件對(duì)象有一個(gè)xreadlines()方法,它返回一個(gè)迭代器,一次讀取文件的一行。這在for循環(huán)中尤其有用。事實(shí)上,后來(lái)的Python 2版本給文件對(duì)象本身添加了這樣的功能。
在Python 3里,xreadlines()方法不再可用了。2to3可以解決簡(jiǎn)單的情況,但是一些邊緣案例則需要人工介入。
NotesPython 2Python 3
①
for line in a_file.xreadlines():
for line in a_file:
②
for line in a_file.xreadlines(5):
no change (broken)
如果你以前調(diào)用沒有參數(shù)的xreadlines(),2to3會(huì)把它轉(zhuǎn)換成文件對(duì)象本身。在Python 3里,這種轉(zhuǎn)換后的代碼可以完成前同樣的工作:一次讀取文件的一行,然后執(zhí)行for循環(huán)的循環(huán)體。
如果你以前使用一個(gè)參數(shù)(每次讀取的行數(shù))調(diào)用xreadlines(),2to3不能為你完成從Python 2到Python 3的轉(zhuǎn)換,你的代碼會(huì)以這樣的方式失敗:AttributeError: '_io.TextIOWrapper' object has no attribute 'xreadlines'。你可以手工的把xreadlines()改成readlines()以使代碼能在Python 3下工作。(readline()方法在Python 3里返回迭代器,所以它跟Python 2里的xreadlines()效率是不相上下的。)
?
使用元組而非多個(gè)參數(shù)的lambda函數(shù)
在Python 2里,你可以定義匿名lambda函數(shù)(anonymous lambda function),通過(guò)指定作為參數(shù)的元組的元素個(gè)數(shù),使這個(gè)函數(shù)實(shí)際上能夠接收多個(gè)參數(shù)。事實(shí)上,Python 2的解釋器把這個(gè)元組“解開”(unpack)成命名參數(shù)(named arguments),然后你可以在lambda函數(shù)里引用它們(通過(guò)名字)。在Python 3里,你仍然可以傳遞一個(gè)元組作為lambda函數(shù)的參數(shù),但是Python解釋器不會(huì)把它解析成命名參數(shù)。你需要通過(guò)位置索引(positional index)來(lái)引用每個(gè)參數(shù)。
NotesPython 2Python 3
①
lambda (x,): x + f(x)
lambda x1: x1[0] + f(x1[0])
②
lambda (x, y): x + f(y)
lambda x_y: x_y[0] + f(x_y[1])
③
lambda (x, (y, z)): x + y + z
lambda x_y_z: x_y_z[0] + x_y_z[1][0] + x_y_z[1][1]
④
lambda x, y, z: x + y + z
unchanged
如果你已經(jīng)定義了一個(gè)lambda函數(shù),它使用包含一個(gè)元素的元組作為參數(shù),在Python 3里,它會(huì)被轉(zhuǎn)換成一個(gè)包含到x1[0]的引用的lambda函數(shù)。x1是2to3腳本基于原來(lái)元組里的命名參數(shù)自動(dòng)生成的。
使用含有兩個(gè)元素的元組(x, y)作為參數(shù)的lambda函數(shù)被轉(zhuǎn)換為x_y,它有兩個(gè)位置參數(shù),即x_y[0]和x_y[1]。
2to3腳本甚至可以處理使用嵌套命名參數(shù)的元組作為參數(shù)的lambda函數(shù)。產(chǎn)生的結(jié)果代碼有點(diǎn)難以閱讀,但是它在Python 3下跟原來(lái)的代碼在Python 2下的效果是一樣的。
你可以定義使用多個(gè)參數(shù)的lambda函數(shù)。如果沒有括號(hào)包圍在參數(shù)周圍,Python 2會(huì)把它當(dāng)作一個(gè)包含多個(gè)參數(shù)的lambda函數(shù);在這個(gè)lambda函數(shù)體里,你通過(guò)名字引用這些參數(shù),就像在其他類型的函數(shù)里所做的一樣。這種語(yǔ)法在Python 3里仍然有效。
特殊的方法屬性
在Python 2里,類方法可以訪問(wèn)到定義他們的類對(duì)象(class object),也能訪問(wèn)方法對(duì)象(method object)本身。im_self是類的實(shí)例對(duì)象;im_func是函數(shù)對(duì)象,im_class是類本身。在Python 3里,這些屬性被重新命名,以遵循其他屬性的命名約定。
NotesPython 2Python 3
aClassInstance.aClassMethod.im_func
aClassInstance.aClassMethod.__func__
aClassInstance.aClassMethod.im_self
aClassInstance.aClassMethod.__self__
aClassInstance.aClassMethod.im_class
aClassInstance.aClassMethod.__self__.__class__
__nonzero__特殊方法
在Python 2里,你可以創(chuàng)建自己的類,并使他們能夠在布爾上下文(boolean context)中使用。舉例來(lái)說(shuō),你可以實(shí)例化這個(gè)類,并把這個(gè)實(shí)例對(duì)象用在一個(gè)if語(yǔ)句中。為了實(shí)現(xiàn)這個(gè)目的,你定義一個(gè)特別的__nonzero__()方法,它的返回值為True或者False,當(dāng)實(shí)例對(duì)象處在布爾上下文中的時(shí)候這個(gè)方法就會(huì)被調(diào)用 。在Python 3里,你仍然可以完成同樣的功能,但是這個(gè)特殊方法的名字變成了__bool__()。
NotesPython 2Python 3
①
class A:
def __nonzero__(self):
pass
class A:
def __bool__(self):
pass
②
class A:
def __nonzero__(self, x, y):
pass
no change
當(dāng)在布爾上下文使用一個(gè)類對(duì)象時(shí),Python 3會(huì)調(diào)用__bool__(),而非__nonzero__()。
然而,如果你有定義了一個(gè)使用兩個(gè)參數(shù)的__nonzero__()方法,2to3腳本會(huì)假設(shè)你定義的這個(gè)方法有其他用處,因此不會(huì)對(duì)代碼做修改。
八進(jìn)制類型
在Python 2和Python 3之間,定義八進(jìn)制(octal)數(shù)的語(yǔ)法有輕微的改變。
NotesPython 2Python 3
x = 0755
x = 0o755
sys.maxint
由于長(zhǎng)整型和整型被整合在一起了,sys.maxint常量不再精確。但是因?yàn)檫@個(gè)值對(duì)于檢測(cè)特定平臺(tái)的能力還是有用處的,所以它被Python 3保留,并且重命名為sys.maxsize。
NotesPython 2Python 3
①
from sys import maxint
from sys import maxsize
②
a_function(sys.maxint)
a_function(sys.maxsize)
maxint變成了maxsize。
所有的sys.maxint都變成了sys.maxsize。
全局函數(shù)callable()
在Python 2里,你可以使用全局函數(shù)callable()來(lái)檢查一個(gè)對(duì)象是否可調(diào)用(callable,比如函數(shù))。在Python 3里,這個(gè)全局函數(shù)被取消了。為了檢查一個(gè)對(duì)象是否可調(diào)用,可以檢查特殊方法__call__()的存在性。
NotesPython 2Python 3
callable(anything)
hasattr(anything, '__call__')
全局函數(shù)zip()
在Python 2里,全局函數(shù)zip()可以使用任意多個(gè)序列作為參數(shù),它返回一個(gè)由元組構(gòu)成的列表。第一個(gè)元組包含了每個(gè)序列的第一個(gè)元素;第二個(gè)元組包含了每個(gè)序列的第二個(gè)元素;依次遞推下去。在Python 3里,zip()返回一個(gè)迭代器,而非列表。
NotesPython 2Python 3
①
zip(a, b, c)
list(zip(a, b, c))
②
d.join(zip(a, b, c))
no change
最簡(jiǎn)單的形式,你可以通過(guò)調(diào)用list()函數(shù)包裝zip()的返回值來(lái)恢復(fù)zip()函數(shù)以前的功能,list()函數(shù)會(huì)遍歷這個(gè)zip()函數(shù)返回的迭代器,然后返回結(jié)果的列表表示。
在已經(jīng)會(huì)遍歷序列所有元素的上下文環(huán)境里(比如這里對(duì)join()方法的調(diào)用),zip()返回的迭代器能夠正常工作。2to3腳本會(huì)檢測(cè)到這些情況,不會(huì)對(duì)你的代碼作出改變。
StandardError異常
在Python 2里,StandardError是除了StopIteration,GeneratorExit,KeyboardInterrupt,SystemExit之外所有其他內(nèi)置異常的基類。在Python 3里,StandardError已經(jīng)被取消了;使用Exception替代。
NotesPython 2Python 3
x = StandardError()
x = Exception()
x = StandardError(a, b, c)
x = Exception(a, b, c)
types模塊中的常量
types模塊里各種各樣的常量能幫助你決定一個(gè)對(duì)象的類型。在Python 2里,它包含了代表所有基本數(shù)據(jù)類型的常量,如dict和int。在Python 3里,這些常量被已經(jīng)取消了。只需要使用基礎(chǔ)類型的名字來(lái)替代。
NotesPython 2Python 3
types.UnicodeType
str
types.StringType
bytes
types.DictType
dict
types.IntType
int
types.LongType
int
types.ListType
list
types.NoneType
type(None)
types.BooleanType
bool
types.BufferType
memoryview
types.ClassType
type
types.ComplexType
complex
types.EllipsisType
type(Ellipsis)
types.FloatType
float
types.ObjectType
object
types.NotImplementedType
type(NotImplemented)
types.SliceType
slice
types.TupleType
tuple
types.TypeType
type
types.XRangeType
range
?types.StringType被映射為bytes,而非str,因?yàn)镻ython 2里的“string”(非Unicode編碼的字符串,即普通字符串)事實(shí)上只是一些使用某種字符編碼的字節(jié)序列(a sequence of bytes)。
全局函數(shù)isinstance()
isinstance()函數(shù)檢查一個(gè)對(duì)象是否是一個(gè)特定類(class)或者類型(type)的實(shí)例。在Python 2里,你可以傳遞一個(gè)由類型(types)構(gòu)成的元組給isinstance(),如果該對(duì)象是元組里的任意一種類型,函數(shù)返回True。在Python 3里,你依然可以這樣做,但是不推薦使用把一種類型作為參數(shù)傳遞兩次。
NotesPython 2Python 3
isinstance(x, (int, float, int))
isinstance(x, (int, float))
basestring數(shù)據(jù)類型
Python 2有兩種字符串類型:Unicode編碼的字符串和非Unicode編碼的字符串。但是其實(shí)還有另外 一種類型,即basestring。它是一個(gè)抽象數(shù)據(jù)類型,是str和unicode類型的超類(superclass)。它不能被直接調(diào)用或者實(shí)例化,但是你可以把它作為isinstance()的參數(shù)來(lái)檢測(cè)一個(gè)對(duì)象是否是一個(gè)Unicode字符串或者非Unicode字符串。在Python 3里,只有一種字符串類型,所以basestring就沒有必要再存在了。
NotesPython 2Python 3
isinstance(x, basestring)
isinstance(x, str)
itertools模塊
Python 2.3引入了itertools模塊,它定義了全局函數(shù)zip(),map(),filter()的變體(variant),這些變體的返回類型為迭代器,而非列表。在Python 3里,由于這些全局函數(shù)的返回類型本來(lái)就是迭代器,所以這些itertools里的這些變體函數(shù)就被取消了。(在itertools模塊里仍然還有許多其他的有用的函數(shù),而不僅僅是以上列出的這些。)
NotesPython 2Python 3
①
itertools.izip(a, b)
zip(a, b)
②
itertools.imap(a, b)
map(a, b)
③
itertools.ifilter(a, b)
filter(a, b)
④
from itertools import imap, izip, foo
from itertools import foo
使用全局的zip()函數(shù),而非itertools.izip()。
使用map()而非itertools.imap()。
itertools.ifilter()變成了filter()。
itertools模塊在Python 3里仍然存在,它只是不再包含那些已經(jīng)轉(zhuǎn)移到全局名字空間的函數(shù)。2to3腳本能夠足夠智能地去移除那些不再有用的導(dǎo)入語(yǔ)句,同時(shí)保持其他的導(dǎo)入語(yǔ)句的完整性。
sys.exc_type, sys.exc_value, sys.exc_traceback
處理異常的時(shí)候,在sys模塊里有三個(gè)你可以訪問(wèn)的變量:sys.exc_type,sys.exc_value,sys.exc_traceback。(實(shí)際上這些在Python 1的時(shí)代就有。)從Python 1.5開始,由于新出的sys.exc_info,不再推薦使用這三個(gè)變量了,這是一個(gè)包含所有以上三個(gè)元素的元組。在Python 3里,這三個(gè)變量終于不再存在了;這意味著,你必須使用sys.exc_info。
NotesPython 2Python 3
sys.exc_type
sys.exc_info()[0]
sys.exc_value
sys.exc_info()[1]
sys.exc_traceback
sys.exc_info()[2]
對(duì)元組的列表解析
在Python 2里,如果你需要編寫一個(gè)遍歷元組的列表解析,你不需要在元組值的周圍加上括號(hào)。在Python 3里,這些括號(hào)是必需的。
NotesPython 2Python 3
[i for i in 1, 2]
[i for i in (1, 2)]
os.getcwdu()函數(shù)
Python 2有一個(gè)叫做os.getcwd()的函數(shù),它將當(dāng)前的工作目錄作為一個(gè)(非Unicode編碼的)字符串返回。由于現(xiàn)代的文件系統(tǒng)能夠處理能何字符編碼的目錄名,Python 2.3引入了os.getcwdu()函數(shù)。os.getcwdu()函數(shù)把當(dāng)前工作目錄用Unicode編碼的字符串返回。在Python 3里,由于只有一種字符串類型(Unicode類型的),所以你只需要os.getcwd()就可以了。
NotesPython 2Python 3
os.getcwdu()
os.getcwd()
元類(metaclass)
在Python 2里,你可以通過(guò)在類的聲明中定義metaclass參數(shù),或者定義一個(gè)特殊的類級(jí)別的(class-level)__metaclass__屬性,來(lái)創(chuàng)建元類。在Python 3里,__metaclass__屬性已經(jīng)被取消了。
NotesPython 2Python 3
①
class C(metaclass=PapayaMeta):
pass
unchanged
②
class Whip:
__metaclass__ = PapayaMeta
class Whip(metaclass=PapayaMeta):
pass
③
class C(Whipper, Beater):
__metaclass__ = PapayaMeta
class C(Whipper, Beater, metaclass=PapayaMeta):
pass
在聲明類的時(shí)候聲明metaclass參數(shù),這在Python 2和Python 3里都有效,它們是一樣的。
在類的定義里聲明__metaclass__屬性在Python 2里有效,但是在Python 3里不再有效。
2to3能夠構(gòu)建一個(gè)有效的類聲明,即使這個(gè)類繼承自多個(gè)父類。
關(guān)于代碼風(fēng)格
以下所列的“修補(bǔ)”(fixes)實(shí)質(zhì)上并不算真正的修補(bǔ)。意思就是,他們只是代碼的風(fēng)格上的事情,而不涉及到代碼的本質(zhì)。但是Python的開發(fā)者們?cè)谑沟么a風(fēng)格盡可能一致方面非常有興趣(have a vested interest)。為此,有一個(gè)專門o描述Python代碼風(fēng)格的官方指導(dǎo)手冊(cè) — 細(xì)致到能使人痛苦 — 都是一些你不太可能關(guān)心的在各種各樣的細(xì)節(jié)上的挑剔。鑒于2to3為轉(zhuǎn)換代碼提供了一個(gè)這么好的條件,腳本的作者們添加了一些可選的特性以使你的代碼更具可讀性。
set()字面值(literal)(顯式的)
在Python 2城,定義一個(gè)字面值集合(literal set)的唯一方法就是調(diào)用set(a_sequence)。在Python 3里這仍然有效,但是使用新的標(biāo)注記號(hào)(literal notation):大括號(hào)({})是一種更清晰的方法。這種方法除了空集以外都有效,因?yàn)樽值湟灿么罄ㄌ?hào)標(biāo)記,所以{}表示一個(gè)空的字典,而不是一個(gè)空集。
?2to3腳本默認(rèn)不會(huì)修復(fù)set()字面值。為了開啟這個(gè)功能,在命令行調(diào)用2to3的時(shí)候指定-f set_literal參數(shù)。
NotesBeforeAfter
set([1, 2, 3])
{1, 2, 3}
set((1, 2, 3))
{1, 2, 3}
set([i for i in a_sequence])
{i for i in a_sequence}
全局函數(shù)buffer()(顯式的)
用C實(shí)現(xiàn)的Python對(duì)象可以導(dǎo)出一個(gè)“緩沖區(qū)接口”(buffer interface),它允許其他的Python代碼直接讀寫一塊內(nèi)存。(這聽起來(lái)很強(qiáng)大,它也同樣可怕。)在Python 3里,buffer()被重新命名為memoryview()。(實(shí)際的修改更加復(fù)雜,但是你幾乎可以忽略掉這些不同之處。)
?2to3腳本默認(rèn)不會(huì)修復(fù)buffer()函數(shù)。為了開啟這個(gè)功能,在命令行調(diào)用2to3的時(shí)候指定-f buffer參數(shù)。
NotesBeforeAfter
x = buffer(y)
x = memoryview(y)
逗號(hào)周圍的空格(顯式的)
盡管Python對(duì)用于縮進(jìn)和凸出(indenting and outdenting)的空格要求很嚴(yán)格,但是對(duì)于空格在其他方面的使用Python還是很自由的。在列表,元組,集合和字典里,空格可以出現(xiàn)在逗號(hào)的前面或者后面,這不會(huì)有什么壞影響。但是,Python代碼風(fēng)格指導(dǎo)手冊(cè)上指出,逗號(hào)前不能有空格,逗號(hào)后應(yīng)該包含一個(gè)空格。盡管這純粹只是一個(gè)美觀上的考量(代碼仍然可以正常工作,在Python 2和Python 3里都可以),但是2to3腳本可以依據(jù)手冊(cè)上的標(biāo)準(zhǔn)為你完成這個(gè)修復(fù)。
?2to3腳本默認(rèn)不會(huì)修復(fù)逗號(hào)周圍的空格。為了開啟這個(gè)功能,在命令行調(diào)用2to3的時(shí)候指定-f wscomma參數(shù)。
NotesBeforeAfter
a ,b
a, b
{a :b}
{a: b}
慣例(Common idioms)(顯式的)
在Python社區(qū)里建立起來(lái)了許多慣例。有一些比如while 1: loop,它可以追溯到Python 1。(Python直到Python 2.3才有真正意義上的布爾類型,所以開發(fā)者以前使用1和0替代。)當(dāng)代的Python程序員應(yīng)該鍛煉他們的大腦以使用這些慣例的現(xiàn)代版。
?2to3腳本默認(rèn)不會(huì)為這些慣例做修復(fù)。為了開啟這個(gè)功能,在命令行調(diào)用2to3的時(shí)候指定-f idioms參數(shù)。
NotesBeforeAfter
while 1:
do_stuff()
while True:
do_stuff()
type(x) == T
isinstance(x, T)
type(x) is T
isinstance(x, T)
a_list = list(a_sequence)
a_list.sort()
do_stuff(a_list)
a_list = sorted(a_sequence)
do_stuff(a_list)
總結(jié)
以上是生活随笔為你收集整理的python3语法都相同吗_python2 与 python3 语法区别--转的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ArcPy常用函数梳理
- 下一篇: crontab 每周五_crontab定