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)境下。為了簡化這個(gè)轉(zhuǎn)換過程,Python 3自帶了一個(gè)叫做2to3的實(shí)用腳本(Utility Script),這個(gè)腳本會將你的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語句
在Python 2里,print是一個(gè)語句。無論你想輸出什么,只要將它們放在print關(guān)鍵字后邊就可以。在Python 3里,print()是一個(gè)函數(shù)。就像其他的函數(shù)一樣,print()需要你將想要輸出的東西作為參數(shù)傳給它。
| 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) |
Unicode字符串
Python 2有兩種字符串類型:Unicode字符串和非Unicode字符串。Python 3只有一種類型:Unicode字符串(Unicode strings)。
| u'PapayaWhip' | 'PapayaWhip' |
| ur'PapayaWhip\foo' | r'PapayaWhip\foo' |
全局函數(shù)unicode()
Python 2有兩個(gè)全局函數(shù)可以把對象強(qiáng)制轉(zhuǎn)換成字符串:unicode()把對象轉(zhuǎn)換成Unicode字符串,還有str()把對象轉(zhuǎn)換為非Unicode字符串。Python 3只有一種字符串類型,Unicode字符串,所以str()函數(shù)即可完成所有的功能。(unicode()函數(shù)在Python 3里不再存在了。)
| unicode(anything) | str(anything) |
long?長整型
Python 2有為非浮點(diǎn)數(shù)準(zhǔn)備的int和long類型。int類型的最大值不能超過sys.maxint,而且這個(gè)最大值是平臺相關(guān)的??梢酝ㄟ^在數(shù)字的末尾附上一個(gè)L來定義長整型,顯然,它比int類型表示的數(shù)字范圍更大。在Python 3里,只有一種整數(shù)類型int,大多數(shù)情況下,它很像Python 2里的長整型。由于已經(jīng)不存在兩種類型的整數(shù),所以就沒有必要使用特殊的語法去區(qū)別他們。
進(jìn)一步閱讀:PEP?237:統(tǒng)一長整型和整型。
| 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) |
<> 比較運(yùn)算符
Python 2支持<>作為!=的同義詞。Python 3只支持!=,不再支持<>了。
| if x <> y: | if x != y: |
| if x <> y <> z: | if x != y != z: |
字典類方法has_key()
在Python 2里,字典對象的has_key()方法用來測試字典是否包含特定的鍵(key)。Python 3不再支持這個(gè)方法了。你需要使用in運(yùn)算符。
| 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) |
返回列表的字典類方法
在Python 2里,許多字典類方法的返回值是列表。其中最常用方法的有keys,items和values。在Python 3里,所有以上方法的返回值改為動(dòng)態(tài)視圖(dynamic view)。在一些上下文環(huán)境里,這種改變并不會產(chǎn)生影響。如果這些方法的返回值被立即傳遞給另外一個(gè)函數(shù),并且那個(gè)函數(shù)會遍歷整個(gè)序列,那么以上方法的返回值是列表或者視圖并不會產(chǎn)生什么不同。在另外一些情況下,Python 3的這些改變干系重大。如果你期待一個(gè)能被獨(dú)立尋址元素的列表,那么Python 3的這些改變將會使你的代碼卡住(choke),因?yàn)橐晥D(view)不支持索引(indexing)。
| 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 |
被重命名或者重新組織的模塊
從Python 2到Python 3,標(biāo)準(zhǔn)庫里的一些模塊已經(jīng)被重命名了。還有一些相互關(guān)聯(lián)的模塊也被組合或者重新組織,以使得這種關(guān)聯(lián)更有邏輯性。
http
在Python 3里,幾個(gè)相關(guān)的HTTP模塊被組合成一個(gè)單獨(dú)的包,即http。
| import?httplib | import http.client |
| import?Cookie | import http.cookies |
| import?cookielib | import http.cookiejar |
| import BaseHTTPServer import SimpleHTTPServer import CGIHttpServer | import http.server |
urllib
Python 2有一些用來分析,編碼和獲取URL的模塊,但是這些模塊就像老鼠窩一樣相互重疊。在Python 3里,這些模塊被重構(gòu)、組合成了一個(gè)單獨(dú)的包,即urllib。
| 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 |
我是否有提到2to3也會重寫你的函數(shù)調(diào)用?比如,如果你的Python 2代碼里導(dǎo)入了urllib模塊,調(diào)用了urllib.urlopen()函數(shù)獲取數(shù)據(jù),2to3會同時(shí)修改import語句和函數(shù)調(diào)用。
| 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包中合適的模塊。
| 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è)通過HTTP協(xié)議執(zhí)行遠(yuǎn)程RPC調(diào)用的輕重級方法。一些XML-RPC客戶端和XML-RPC服務(wù)端的實(shí)現(xiàn)庫現(xiàn)在被組合到了獨(dú)立的包,即xmlrpc。
| import?xmlrpclib | import xmlrpc.client |
| import DocXMLRPCServer import SimpleXMLRPCServer | import xmlrpc.server |
其他模塊
| 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 |
包內(nèi)的相對導(dǎo)入
包是由一組相關(guān)聯(lián)的模塊共同組成的單個(gè)實(shí)體。在Python 2的時(shí)候,為了實(shí)現(xiàn)同一個(gè)包內(nèi)模塊的相互引用,你會使用import foo或者from foo import Bar。Python 2解釋器會先在當(dāng)前目錄里搜索foo.py,然后再去Python搜索路徑(sys.path)里搜索。在Python 3里這個(gè)過程有一點(diǎn)不同。Python 3不會首先在當(dāng)前路徑搜索,它會直接在Python的搜索路徑里尋找。如果你想要包里的一個(gè)模塊導(dǎo)入包里的另外一個(gè)模塊,你需要顯式地提供兩個(gè)模塊的相對路徑。
假設(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è)類。你會怎樣做?
| import constants | from . import constants |
| from mbcharsetprober import MultiByteCharSetProber | from .mbcharsetprober import MultiByteCharsetProber |
迭代器方法next()
在Python 2里,迭代器有一個(gè)next()方法,用來返回序列里的下一項(xiàng)。在Python 3里這同樣成立,但是現(xiàn)在有了一個(gè)新的全局的函數(shù)next(),它使用一個(gè)迭代器作為參數(shù)。
| 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__() |
全局函數(shù)filter()
在Python 2里,filter()方法返回一個(gè)列表,這個(gè)列表是通過一個(gè)返回值為True或者False的函數(shù)來檢測序列里的每一項(xiàng)得到的。在Python 3里,filter()函數(shù)返回一個(gè)迭代器,不再是列表。
| 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 |
全局函數(shù)map()
跟filter()作的改變一樣,map()函數(shù)現(xiàn)在返回一個(gè)迭代器。(在Python 2里,它返回一個(gè)列表。)
| 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 |
全局函數(shù)reduce()
在Python 3里,reduce()函數(shù)已經(jīng)被從全局名字空間里移除了,它現(xiàn)在被放置在fucntools模塊里。
| 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)。你也可以通過直接調(diào)用這個(gè)函數(shù),在列表前添加一個(gè)星號(*)作為參數(shù)傳遞給它來完成同樣的事情。在Python 3里,apply()函數(shù)不再存在了;必須使用星號標(biāo)記法。
| 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) |
全局函數(shù)intern()
在Python 2里,你可以用intern()函數(shù)作用在一個(gè)字符串上來限定(intern)它以達(dá)到性能優(yōu)化。在Python 3里,intern()函數(shù)被轉(zhuǎn)移到sys模塊里了。
| intern(aString) | sys.intern(aString) |
exec語句
就像print語句在Python 3里變成了一個(gè)函數(shù)一樣,exec語句也是這樣的。exec()函數(shù)使用一個(gè)包含任意Python代碼的字符串作為參數(shù),然后就像執(zhí)行語句或者表達(dá)式一樣執(zhí)行它。exec()跟eval()是相似的,但是exec()更加強(qiáng)大并更具有技巧性。eval()函數(shù)只能執(zhí)行單獨(dú)一條表達(dá)式,但是exec()能夠執(zhí)行多條語句,導(dǎo)入(import),函數(shù)聲明?—?實(shí)際上整個(gè)Python程序的字符串表示也可以。
| 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) |
execfile語句
就像以前的exec語句,Python 2里的execfile語句也可以像執(zhí)行Python代碼那樣使用字符串。不同的是exec使用字符串,而execfile則使用文件。在Python 3里,execfile語句已經(jīng)被去掉了。如果你真的想要執(zhí)行一個(gè)文件里的Python代碼(但是你不想導(dǎo)入它),你可以通過打開這個(gè)文件,讀取它的內(nèi)容,然后調(diào)用compile()全局函數(shù)強(qiáng)制Python解釋器編譯代碼,然后調(diào)用新的exec()函數(shù)。
| execfile('a_filename') | exec(compile(open('a_filename').read(), 'a_filename', 'exec')) |
repr(反引號)
在Python 2里,為了得到一個(gè)任意對象的字符串表示,有一種把對象包裝在反引號里(比如`x`)的特殊語法。在Python 3里,這種能力仍然存在,但是你不能再使用反引號獲得這種字符串表示了。你需要使用全局函數(shù)repr()。
| `x` | repr(x) |
| `'PapayaWhip' + `2`` | repr('PapayaWhip' + repr(2)) |
try...except語句
從Python 2到Python 3,捕獲異常的語法有些許變化。
| try:import mymodule except ImportError, epass | try:import mymodule except ImportError as e:pass |
| try:import mymodule except (RuntimeError, ImportError), epass | try:import mymodule except (RuntimeError, ImportError) as e:pass |
| try:import mymodule except ImportError:pass | no change |
| try:import mymodule except:pass | no change |
?在導(dǎo)入模塊(或者其他大多數(shù)情況)的時(shí)候,你絕對不應(yīng)該使用這種方法(指以上的fallback)。不然的話,程序可能會捕獲到像KeyboardInterrupt(如果用戶按Ctrl-C來中斷程序)這樣的異常,從而使調(diào)試變得更加困難。
raise語句
Python 3里,拋出自定義異常的語法有細(xì)微的變化。
| 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 |
生成器的throw方法
在Python 2里,生成器有一個(gè)throw()方法。調(diào)用a_generator.throw()會在生成器被暫停的時(shí)候拋出一個(gè)異常,然后返回由生成器函數(shù)獲取的下一個(gè)值。在Python 3里,這種功能仍然可用,但是語法上有一點(diǎn)不同。
| a_generator.throw(MyException) | no change |
| a_generator.throw(MyException, 'error message') | a_generator.throw(MyException('error message')) |
| a_generator.throw('error message') | unsupported |
全局函數(shù)xrange()
在Python 2里,有兩種方法來獲得一定范圍內(nèi)的數(shù)字:range(),它返回一個(gè)列表,還有range(),它返回一個(gè)迭代器。在Python 3里,range()返回迭代器,xrange()不再存在了。
| 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 |
全局函數(shù)raw_input()和input()
Python 2有兩個(gè)全局函數(shù),用來在命令行請求用戶輸入。第一個(gè)叫做input(),它等待用戶輸入一個(gè)Python表達(dá)式(然后返回結(jié)果)。第二個(gè)叫做raw_input(),用戶輸入什么它就返回什么。這讓初學(xué)者非常困惑,并且這被廣泛地看作是Python語言的一個(gè)“肉贅”(wart)。Python 3通過重命名raw_input()為input(),從而切掉了這個(gè)肉贅,所以現(xiàn)在的input()就像每個(gè)人最初期待的那樣工作。
| raw_input() | input() |
| raw_input('prompt') | input('prompt') |
| input() | eval(input()) |
函數(shù)屬性func_*
在Python 2里,函數(shù)的里的代碼可以訪問到函數(shù)本身的特殊屬性。在Python 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__ |
I/O方法xreadlines()
在Python 2里,文件對象有一個(gè)xreadlines()方法,它返回一個(gè)迭代器,一次讀取文件的一行。這在for循環(huán)中尤其有用。事實(shí)上,后來的Python 2版本給文件對象本身添加了這樣的功能。
在Python 3里,xreadlines()方法不再可用了。2to3可以解決簡單的情況,但是一些邊緣案例則需要人工介入。
| for line in a_file.xreadlines(): | for line in a_file: |
| for line in a_file.xreadlines(5): | no change (broken) |
?
使用元組而非多個(gè)參數(shù)的lambda函數(shù)
在Python 2里,你可以定義匿名lambda函數(shù)(anonymous?lambda?function),通過指定作為參數(shù)的元組的元素個(gè)數(shù),使這個(gè)函數(shù)實(shí)際上能夠接收多個(gè)參數(shù)。事實(shí)上,Python 2的解釋器把這個(gè)元組“解開”(unpack)成命名參數(shù)(named arguments),然后你可以在lambda函數(shù)里引用它們(通過名字)。在Python 3里,你仍然可以傳遞一個(gè)元組作為lambda函數(shù)的參數(shù),但是Python解釋器不會把它解析成命名參數(shù)。你需要通過位置索引(positional index)來引用每個(gè)參數(shù)。
| 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 |
特殊的方法屬性
在Python 2里,類方法可以訪問到定義他們的類對象(class object),也能訪問方法對象(method object)本身。im_self是類的實(shí)例對象;im_func是函數(shù)對象,im_class是類本身。在Python 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)中使用。舉例來說,你可以實(shí)例化這個(gè)類,并把這個(gè)實(shí)例對象用在一個(gè)if語句中。為了實(shí)現(xiàn)這個(gè)目的,你定義一個(gè)特別的__nonzero__()方法,它的返回值為True或者False,當(dāng)實(shí)例對象處在布爾上下文中的時(shí)候這個(gè)方法就會被調(diào)用 。在Python 3里,你仍然可以完成同樣的功能,但是這個(gè)特殊方法的名字變成了__bool__()。
| class A:def __nonzero__(self):pass | class A:def __bool__(self):pass |
| class A:def __nonzero__(self, x, y):pass | no change |
八進(jìn)制類型
在Python 2和Python 3之間,定義八進(jìn)制(octal)數(shù)的語法有輕微的改變。
| x = 0755 | x = 0o755 |
sys.maxint
由于長整型和整型被整合在一起了,sys.maxint常量不再精確。但是因?yàn)檫@個(gè)值對于檢測特定平臺的能力還是有用處的,所以它被Python 3保留,并且重命名為sys.maxsize。
| from sys import?maxint | from sys import?maxsize |
| a_function(sys.maxint) | a_function(sys.maxsize) |
全局函數(shù)callable()
在Python 2里,你可以使用全局函數(shù)callable()來檢查一個(gè)對象是否可調(diào)用(callable,比如函數(shù))。在Python 3里,這個(gè)全局函數(shù)被取消了。為了檢查一個(gè)對象是否可調(diào)用,可以檢查特殊方法__call__()的存在性。
| 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è)迭代器,而非列表。
| zip(a, b, c) | list(zip(a, b, c)) |
| d.join(zip(a, b, c)) | no change |
StandardError異常
在Python 2里,StandardError是除了StopIteration,GeneratorExit,KeyboardInterrupt,SystemExit之外所有其他內(nèi)置異常的基類。在Python 3里,StandardError已經(jīng)被取消了;使用Exception替代。
| x = StandardError() | x = Exception() |
| x = StandardError(a, b, c) | x = Exception(a, b, c) |
types模塊中的常量
types模塊里各種各樣的常量能幫助你決定一個(gè)對象的類型。在Python 2里,它包含了代表所有基本數(shù)據(jù)類型的常量,如dict和int。在Python 3里,這些常量被已經(jīng)取消了。只需要使用基礎(chǔ)類型的名字來替代。
| 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è)對象是否是一個(gè)特定類(class)或者類型(type)的實(shí)例。在Python 2里,你可以傳遞一個(gè)由類型(types)構(gòu)成的元組給isinstance(),如果該對象是元組里的任意一種類型,函數(shù)返回True。在Python 3里,你依然可以這樣做,但是不推薦使用把一種類型作為參數(shù)傳遞兩次。
| 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ù)來檢測一個(gè)對象是否是一個(gè)Unicode字符串或者非Unicode字符串。在Python 3里,只有一種字符串類型,所以basestring就沒有必要再存在了。
| isinstance(x, basestring) | isinstance(x, str) |
itertools模塊
Python 2.3引入了itertools模塊,它定義了全局函數(shù)zip(),map(),filter()的變體(variant),這些變體的返回類型為迭代器,而非列表。在Python 3里,由于這些全局函數(shù)的返回類型本來就是迭代器,所以這些itertools里的這些變體函數(shù)就被取消了。(在itertools模塊里仍然還有許多其他的有用的函數(shù),而不僅僅是以上列出的這些。)
| 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 |
sys.exc_type,?sys.exc_value,?sys.exc_traceback
處理異常的時(shí)候,在sys模塊里有三個(gè)你可以訪問的變量: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。
| sys.exc_type | sys.exc_info()[0] |
| sys.exc_value | sys.exc_info()[1] |
| sys.exc_traceback | sys.exc_info()[2] |
對元組的列表解析
在Python 2里,如果你需要編寫一個(gè)遍歷元組的列表解析,你不需要在元組值的周圍加上括號。在Python 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()就可以了。
| os.getcwdu() | os.getcwd() |
元類(metaclass)
在Python 2里,你可以通過在類的聲明中定義metaclass參數(shù),或者定義一個(gè)特殊的類級別的(class-level)__metaclass__屬性,來創(chuàng)建元類。在Python 3里,__metaclass__屬性已經(jīng)被取消了。
| 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 |
關(guān)于代碼風(fēng)格
以下所列的“修補(bǔ)”(fixes)實(shí)質(zhì)上并不算真正的修補(bǔ)。意思就是,他們只是代碼的風(fēng)格上的事情,而不涉及到代碼的本質(zhì)。但是Python的開發(fā)者們在使得代碼風(fēng)格盡可能一致方面非常有興趣(have a vested interest)。為此,有一個(gè)專門o描述Python代碼風(fēng)格的官方指導(dǎo)手冊?—?細(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)注記號(literal notation):大括號({})是一種更清晰的方法。這種方法除了空集以外都有效,因?yàn)樽值湟灿么罄ㄌ枠?biāo)記,所以{}表示一個(gè)空的字典,而不是一個(gè)空集。
?2to3腳本默認(rèn)不會修復(fù)set()字面值。為了開啟這個(gè)功能,在命令行調(diào)用2to3的時(shí)候指定-f set_literal參數(shù)。
| 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對象可以導(dǎo)出一個(gè)“緩沖區(qū)接口”(buffer interface),它允許其他的Python代碼直接讀寫一塊內(nèi)存。(這聽起來很強(qiáng)大,它也同樣可怕。)在Python 3里,buffer()被重新命名為memoryview()。(實(shí)際的修改更加復(fù)雜,但是你幾乎可以忽略掉這些不同之處。)
?2to3腳本默認(rèn)不會修復(fù)buffer()函數(shù)。為了開啟這個(gè)功能,在命令行調(diào)用2to3的時(shí)候指定-f buffer參數(shù)。
| x =?buffer(y) | x =?memoryview(y) |
逗號周圍的空格(顯式的)
盡管Python對用于縮進(jìn)和凸出(indenting and outdenting)的空格要求很嚴(yán)格,但是對于空格在其他方面的使用Python還是很自由的。在列表,元組,集合和字典里,空格可以出現(xiàn)在逗號的前面或者后面,這不會有什么壞影響。但是,Python代碼風(fēng)格指導(dǎo)手冊上指出,逗號前不能有空格,逗號后應(yīng)該包含一個(gè)空格。盡管這純粹只是一個(gè)美觀上的考量(代碼仍然可以正常工作,在Python 2和Python 3里都可以),但是2to3腳本可以依據(jù)手冊上的標(biāo)準(zhǔn)為你完成這個(gè)修復(fù)。
?2to3腳本默認(rèn)不會修復(fù)逗號周圍的空格。為了開啟這個(gè)功能,在命令行調(diào)用2to3的時(shí)候指定-f wscomma參數(shù)。
| a ,b | a, b |
| {a :b} | {a: b} |
慣例(Common idioms)(顯式的)
在Python社區(qū)里建立起來了許多慣例。有一些比如while 1:?loop,它可以追溯到Python 1。(Python直到Python 2.3才有真正意義上的布爾類型,所以開發(fā)者以前使用1和0替代。)當(dāng)代的Python程序員應(yīng)該鍛煉他們的大腦以使用這些慣例的現(xiàn)代版。
?2to3腳本默認(rèn)不會為這些慣例做修復(fù)。為了開啟這個(gè)功能,在命令行調(diào)用2to3的時(shí)候指定-f idioms參數(shù)。
| 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) ? |
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/7493795.html
總結(jié)
以上是生活随笔為你收集整理的python2 与 python3 语法区别--转的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Flume日志收集系统架构详解--转
- 下一篇: java实现sql批量插入参数