溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python2和Python3的區(qū)別及兼容技巧是什么

發(fā)布時間:2020-09-09 15:11:38 來源:億速云 閱讀:212 作者:小新 欄目:編程語言

Python2和Python3的區(qū)別及兼容技巧是什么?這個問題可能是我們?nèi)粘W(xué)習(xí)或工作經(jīng)常見到的。希望通過這個問題能讓你收獲頗深。下面是小編給大家?guī)淼膮⒖純?nèi)容,讓我們一起來看看吧!

Python 2 or 3 ?

Python 3 被欽定為 Python 的未來,于 2008 年末發(fā)布,是目前正在開發(fā)的版本。旨在解決和修正 Python 2 遺留的設(shè)計缺陷、清理代碼庫冗余、追求有且僅有一種最佳實踐方式來執(zhí)行任務(wù)等問題。

起初,由于 Python 3 不能向后兼容的事實,導(dǎo)致了用戶采用緩慢,對初學(xué)者不友好等問題。但在 Python 社區(qū)的努力和決絕態(tài)度下,截至龜爺發(fā)出郵件之前,已經(jīng)有了 21903 個 Packages 可以支持 Python 3.5,其中包括了絕大多數(shù)最受歡迎的封裝庫,與此同時也有越來越多的封裝庫(e.g. Django、Numpy)表示其新版本將不再支持 Python 2。

Python 2.7 于 3.0 之后的 2010 年 7 月 3 日發(fā)布,計劃作為 2.x 的最后一個版本。Python 2.7 的歷史任務(wù)在于通過提供 2 和 3 之間的兼容性措施,使 Python 2.x 的用戶更容易將代碼移植到 Python 3.x 上。那么如果你希望自己的代碼能夠兼容兩個不同的版本,首先你起碼要讓代碼能夠正常的運行在 Python 2.7 上。

注:下文使用 P2 表示 Python 2.7;使用 P3 表示 Python 3.x。

不同與兼容

__future__ 模塊是我們首先需要了解的,該模塊最主要的作用是支持在 P2 中導(dǎo)入那些在 P3 才生效的模塊和函數(shù)。是一個非常優(yōu)秀的兼容性工具庫,在下文中給出的許多 兼容技巧 實例都依賴于它。

特性 在此版本可選 在此版本內(nèi)置 效果

nested_scopes	2.1.0b1	2.2	PEP 227:靜態(tài)嵌套作用域
generators	2.2.0a1	2.3	PEP 255:簡單生成器
division	2.2.0a2	3.0	PEP 238:除法操作符改動
absolute_import	2.5.0a1	3.0	PEP 328:Imports 多行導(dǎo)入與絕對相對路徑
with_statement	2.5.0a1	2.6	PEP 343:with 語句
print_function	2.6.0a2	3.0	PEP 3105:print 語句升級為函數(shù)
unicode_literals	2.6.0a2	3.0	PEP 3112:Bytes 類型

(__future__ 功能列表)

統(tǒng)一不等于語法

P2 支持使用 <> 和 != 表示不等于。

P3 僅支持使用 != 表示不等于。

兼容技巧:

統(tǒng)一使用 != 語法

統(tǒng)一整數(shù)類型

P2 中整數(shù)類型可以細(xì)分為短整型 int 和長整型 long。

P3 廢除了短整型,并統(tǒng)一使用 int 表示長整型(不再有 L 跟在 repr 后面)。

兼容技巧:

# Python 2 only
k = 9223372036854775808L
# Python 2 and 3:
k = 9223372036854775808
# Python 2 only
bigint = 1L
# Python 2 and 3
from future.builtins import int
bigint = int(1)

統(tǒng)一整數(shù)除法

P2 的除法 / 符號實際上具有兩個功能:

當(dāng)兩個操作數(shù)均為整型對象時,進(jìn)行的是地板除(截除小數(shù)部分),返回整型對象;

當(dāng)兩個操作數(shù)存在至少一個浮點型對象時,進(jìn)行的是真除(保留小數(shù)部分),返回浮點型對象。

P3 的除法 / 符號僅僅具有真除的功能,而地板除的功能則交由 // 來完成。

兼容技巧:

# Python 2 only:
assert 2 / 3 == 0
# Python 2 and 3:
assert 2 // 3 == 0
“True division” (float division):
# Python 3 only:
assert 3 / 2 == 1.5
# Python 2 and 3:
from __future__ import division    # (at top of module)

統(tǒng)一縮進(jìn)語法

P2 可以混合使用 tab 和 space 兩種方式來進(jìn)行縮進(jìn)(1 個 tab == 8 個 space),但實際上這一特性并非所有 IDE 都能夠支持,會因此出現(xiàn)同樣的代碼無法跨 IDE 運行的情況。

P3 統(tǒng)一使用 tab 作為縮進(jìn),如果 tab 和 space 同時存在,就會觸發(fā)異常:

TabError: inconsistent use of tabs and spaces in indentation.

兼容技巧:

統(tǒng)一使用 tab 作為縮進(jìn)。

統(tǒng)一類定義

P2 同時支持新式類(object)和老式類。

P3 則統(tǒng)一使用新式類,并且只有使用新式類才能應(yīng)用多重繼承。

兼容技巧:

統(tǒng)一使用新式類。

統(tǒng)一字符編碼類型

P2 默認(rèn)使用 ASCII 字符編碼,但因為 ASCII 只支持?jǐn)?shù)百個字符,并不能靈活的滿足非英文字符,所以 P2 同時也支持 Unicode 這種更強大的字符編碼。不過,由于 P2 同時支持兩套字符編碼,就難免多出了一些標(biāo)識和轉(zhuǎn)換的麻煩。

而 P3 統(tǒng)一使用 Unicode 字符編碼,這節(jié)省了開發(fā)者的時間,同時也可以輕松地在程序中輸入和顯示更多種類的字符。

兼容技巧:

在所有的字符串賦值中均使用前綴 u,或引入 unicode_literals 字符模塊。

# Python 2 only
s1 = 'PythonTab'
s2 = u'Python中文網(wǎng)'
# Python 2 and 3
s1 = u'PythonTab'
s2 = u'Python中文網(wǎng)'
# Python 2 and 3
from __future__ import unicode_literals    # at top of module
s1 = 'PythonTab'
s2 = 'Python中文網(wǎng)'

統(tǒng)一導(dǎo)入模塊的路徑搜索方式

P2 導(dǎo)入一個模塊時首先會搜索當(dāng)前目錄(cwd),若非,則搜索環(huán)境變量路徑(sys.path)。這一特性時常給開發(fā)者帶來困擾,相信大家都曾經(jīng)碰到過,尤其當(dāng)自定義模塊與系統(tǒng)模塊重名的時候;

為了解決這個問題,默認(rèn)的 P3 僅會搜索環(huán)境變量路徑,當(dāng)你需要搜索自定義模塊時,你可以在包管理模式下將項目路徑加入到環(huán)境變量中,然后再使用絕對路徑和相對路徑(以 . 開頭)的方式來導(dǎo)入。

兼容技巧:

統(tǒng)一使用絕對路徑進(jìn)行自定義模塊導(dǎo)入。

修正列表推導(dǎo)式的變量作用域泄露

P2 的列表推倒式中的變量會泄露到全局作用域,例如:

import platform
print('Python', platform.python_version())
i = 1
print('before: I = %s' % i)
print('comprehension: %s' % [i for i in range(5)])
print('after: I = %s' % i)
# OUT
Python 2.7.6
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 4

P3 則解決了這個問題,列表推倒式中的變量不再泄露到全局作用域。

修正非法比較操作異常

P2 能夠?qū)蓚€數(shù)據(jù)類型并不相同的對象進(jìn)行比較。

import platform
print('Python', platform.python_version())
print("[1, 2] > 'foo' = ", [1, 2] > 'foo')
print("(1, 2) > 'foo' = ", (1, 2) > 'foo')
print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))

輸出

Python 2.7.6
[1, 2] > 'foo' = False
(1, 2) > 'foo' = True
[1, 2] > (1, 2) = False

不過,這種看似方便的特性,實際上卻是一個定時炸彈,因為你無法唯一的確定到底是什么原因?qū)е碌姆祷刂禐?False(可能是數(shù)據(jù)比較、也可能是數(shù)據(jù)類型不一致)。

P3 則對其進(jìn)行了修正,如果比較操作數(shù)類型不一致時,會觸發(fā) TypeError 異常。

兼容技巧:

永遠(yuǎn)不要比較數(shù)據(jù)類型不一致的對象。

統(tǒng)一拋出異常語法

P2 同時支持新舊兩種異常觸發(fā)語法:

raise IOError, "file error"   # Old
raise IOError("file error")   # New

兼容技巧

### 拋出異常
# Python 2 only:
raise ValueError, "dodgy value"
# Python 2 and 3:
raise ValueError("dodgy value")
### 使用 traceback 拋出異常
# Python 2 only:
traceback = sys.exc_info()[2]
raise ValueError, "dodgy value", traceback
# Python 3 only:
raise ValueError("dodgy value").with_traceback()
# Python 2 and 3: option 1
from six import reraise as raise_
# or # from future.utils import raise_
traceback = sys.exc_info()[2]
raise_(ValueError, "dodgy value", traceback)
# Python 2 and 3: option 2
from future.utils import raise_with_traceback
raise_with_traceback(ValueError("dodgy value"))
### 異常鏈處理
# Setup:
class DatabaseError(Exception):
    pass
# Python 3 only
class FileDatabase:
    def __init__(self, filename):
        try:
            self.file = open(filename)
        except IOError as exc:
            raise DatabaseError('failed to open') from exc
# Python 2 and 3:
from future.utils import raise_from
class FileDatabase:
    def __init__(self, filename):
        try:
            self.file = open(filename)
        except IOError as exc:
            raise_from(DatabaseError('failed to open'), exc)

P2 實現(xiàn)異常處理也能夠支持兩種語法。

try:
    let_us_cause_a_NameError
except NameError, err:
# except NameError as err:
    print err, '--> our error message'

P3 的異常處理則強制要求使用 as 關(guān)鍵字的方式。

try:
    let_us_cause_a_NameError
except NameError as err:
    print(err, '--> our error message')

統(tǒng)一文件操作函數(shù)

P2 支持使用 file 和 open 兩個函數(shù)來進(jìn)行文件操作。

P3 則統(tǒng)一使用 open 來進(jìn)行文件操作。

兼容技巧:

統(tǒng)一使用 open 函數(shù)。

# Python 2 only:
f = file(pathname)
# Python 2 and 3:
f = open(pathname)

統(tǒng)一列表迭代器生成函數(shù)

P2 支持使用 range 和 xrange 兩個函數(shù)來生成可迭代對象,區(qū)別在于前者返回的是一個列表類型對象,后者返回的是一個類似生成器(惰性求值)的迭代對象,支持無限迭代。所以當(dāng)你需要生成一個很大的序列時,推薦使用 xrange,因為它不會一上來就索取序列所需的所有內(nèi)存空間。如果只對序列進(jìn)行讀操作的話,xrange 方法效率顯然會更高,但是如果要修改序列的元素,或者往序列增刪元素的話,那只能通過 range 方法生成一個 list 對象了。

感謝各位的閱讀!看完上述內(nèi)容,你們對Python2和Python3的區(qū)別及兼容技巧是什么大概了解了嗎?希望文章內(nèi)容對大家有所幫助。如果想了解更多相關(guān)文章內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI