摘要:前言最近之父龜爺終于在官方郵件組落實了的終焉之日。于之后的年月日發布,計劃作為的最后一個版本。統一使用作為縮進,如果和同時存在,就會觸發異常兼容技巧統一使用作為縮進。兼容技巧統一使用內置函數。統一輸出函數中的即是關鍵字又是內置函數。
前言
最近 Python 之父 Guido van Rossum(龜爺)終于在 Python 官方郵件組落實了 Python 2.7 的終焉之日(EOL)。
說的是 Python 2.7 的 EOL 日期最終確定為 2020 年 1 月 1 日,之后不會有任何更新,包括源碼的安全補丁。
所以兼容Python3已經可以說非常必要了,但有些常用的庫還沒有升級到Python3,所以我們看下如何寫出兼容2和3的代碼。
Python 2 or 3 ?
Python 3 被欽定為 Python 的未來,于 2008 年末發布,是目前正在開發的版本。旨在解決和修正 Python 2 遺留的設計缺陷、清理代碼庫冗余、追求有且僅有一種最佳實踐方式來執行任務等問題。
起初,由于 Python 3 不能向后兼容的事實,導致了用戶采用緩慢,對初學者不友好等問題。但在 Python 社區的努力和決絕態度下,截至龜爺發出郵件之前,已經有了 21903 個 Packages 可以支持 Python 3.5,其中包括了絕大多數最受歡迎的封裝庫,與此同時也有越來越多的封裝庫(e.g. Django、Numpy)表示其新版本將不再支持 Python 2。
Python 2.7 于 3.0 之后的 2010 年 7 月 3 日發布,計劃作為 2.x 的最后一個版本。Python 2.7 的歷史任務在于通過提供 2 和 3 之間的兼容性措施,使 Python 2.x 的用戶更容易將代碼移植到 Python 3.x 上。那么如果你希望自己的代碼能夠兼容兩個不同的版本,首先你起碼要讓代碼能夠正常的運行在 Python 2.7 上。
注:下文使用 P2 表示 Python 2.7;使用 P3 表示 Python 3.x。
不同與兼容
future 模塊是我們首先需要了解的,該模塊最主要的作用是支持在 P2 中導入那些在 P3 才生效的模塊和函數。是一個非常優秀的兼容性工具庫,在下文中給出的許多 兼容技巧 實例都依賴于它。
特性 在此版本可選 在此版本內置 效果
nested_scopes 2.1.0b1 2.2 PEP 227:靜態嵌套作用域
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 多行導入與絕對相對路徑
with_statement 2.5.0a1 2.6 PEP 343:with 語句
print_function 2.6.0a2 3.0 PEP 3105:print 語句升級為函數
unicode_literals 2.6.0a2 3.0 PEP 3112:Bytes 類型
(__future__ 功能列表)
統一不等于語法
P2 支持使用 <> 和 != 表示不等于。
P3 僅支持使用 != 表示不等于。
兼容技巧:
統一使用 != 語法
統一整數類型
P2 中整數類型可以細分為短整型 int 和長整型 long。
P3 廢除了短整型,并統一使用 int 表示長整型(不再有 L 跟在 repr 后面)。
兼容技巧:
1
2
3
4
k = 9223372036854775808L
Python 2 and 3:k = 9223372036854775808
1
2
3
4
5
bigint = 1L
Python 2 and 3from future.builtins import int
bigint = int(1)
統一整數除法
P2 的除法 / 符號實際上具有兩個功能:
當兩個操作數均為整型對象時,進行的是地板除(截除小數部分),返回整型對象;
當兩個操作數存在至少一個浮點型對象時,進行的是真除(保留小數部分),返回浮點型對象。
P3 的除法 / 符號僅僅具有真除的功能,而地板除的功能則交由 // 來完成。
兼容技巧:
1
2
3
4
5
assert 2 / 3 == 0
Python 2 and 3:assert 2 // 3 == 0
“True division” (float division):
1
2
3
4
assert 3 / 2 == 1.5
Python 2 and 3:from future import division # (at top of module)
統一縮進語法
P2 可以混合使用 tab 和 space 兩種方式來進行縮進(1 個 tab == 8 個 space),但實際上這一特性并非所有 IDE 都能夠支持,會因此出現同樣的代碼無法跨 IDE 運行的情況。
P3 統一使用 tab 作為縮進,如果 tab 和 space 同時存在,就會觸發異常:
1
TabError: inconsistent use of tabs and spaces in indentation.
兼容技巧:
統一使用 tab 作為縮進。
統一類定義
P2 同時支持新式類(object)和老式類。
P3 則統一使用新式類,并且只有使用新式類才能應用多重繼承。
兼容技巧:
統一使用新式類。
統一字符編碼類型
P2 默認使用 ASCII 字符編碼,但因為 ASCII 只支持數百個字符,并不能靈活的滿足非英文字符,所以 P2 同時也支持 Unicode 這種更強大的字符編碼。不過,由于 P2 同時支持兩套字符編碼,就難免多出了一些標識和轉換的麻煩。
而 P3 統一使用 Unicode 字符編碼,這節省了開發者的時間,同時也可以輕松地在程序中輸入和顯示更多種類的字符。
兼容技巧:
在所有的字符串賦值中均使用前綴 u,或引入 unicode_literals 字符模塊。
1
2
3
4
5
6
7
8
9
10
s1 = "PythonTab"
s2 = u"PythonTab中文網"
s1 = u"PythonTab"
s2 = u"PythonTab中文網"
from future import unicode_literals # at top of module
s1 = "PythonTab"
s2 = "PythonTab中文網"
統一導入模塊的路徑搜索方式
P2 導入一個模塊時首先會搜索當前目錄(cwd),若非,則搜索環境變量路徑(sys.path)。這一特性時常給開發者帶來困擾,相信大家都曾經碰到過,尤其當自定義模塊與系統模塊重名的時候;
為了解決這個問題,默認的 P3 僅會搜索環境變量路徑,當你需要搜索自定義模塊時,你可以在包管理模式下將項目路徑加入到環境變量中,然后再使用絕對路徑和相對路徑(以 . 開頭)的方式來導入。
兼容技巧:
統一使用絕對路徑進行自定義模塊導入。
修正列表推導式的變量作用域泄露
P2 的列表推倒式中的變量會泄露到全局作用域,例如:
1
2
3
4
5
6
7
8
9
10
11
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)
Python 2.7.6
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 4
P3 則解決了這個問題,列表推倒式中的變量不再泄露到全局作用域。
1
2
3
4
5
6
7
8
9
10
11
import platform
print("Python", platform.python_version())
i = 1
print("before: i =", i)
print("comprehension:", [i for i in range(5)])
print("after: i =", i)
Python 3.4.1
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 1
修正非法比較操作異常
P2 能夠對兩個數據類型并不相同的對象進行比較。
1
2
3
4
5
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))
1
2
3
4
Python 2.7.6
[1, 2] > "foo" = False
(1, 2) > "foo" = True
[1, 2] > (1, 2) = False
不過,這種看似方便的特性,實際上卻是一個定時炸彈,因為你無法唯一的確定到底是什么原因導致的返回值為 False(可能是數據比較、也可能是數據類型不一致)。
P3 則對其進行了修正,如果比較操作數類型不一致時,會觸發 TypeError 異常。
兼容技巧:
永遠不要比較數據類型不一致的對象。
統一拋出異常語法
P2 同時支持新舊兩種異常觸發語法:
1
2
raise IOError, "file error" # Old
raise IOError("file error") # New
P3 則統一使用新異常觸發語法,否則會觸發 SyntaxError 異常:
1
raise IOError("file error")
兼容技巧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
raise ValueError("dodgy value").with_traceback()
Python 2 and 3: option 1from six import reraise as raise_
or # from future.utils import raise_traceback = sys.exc_info()[2]
raise_(ValueError, "dodgy value", traceback)
from future.utils import raise_with_traceback
raise_with_traceback(ValueError("dodgy value"))
class DatabaseError(Exception):
passPython 3 only
class FileDatabase:
def __init__(self, filename): try: self.file = open(filename) except IOError as exc: raise DatabaseError("failed to open") from excPython 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 實現異常處理也能夠支持兩種語法。
1
2
3
4
5
try:
let_us_cause_a_NameError
except NameError, err:
except NameError as err:print err, "--> our error message"
P3 的異常處理則強制要求使用 as 關鍵字的方式。
1
2
3
4
try:
let_us_cause_a_NameError
except NameError as err:
print(err, "--> our error message")
兼容技巧:
統一使用 as 關鍵字的異常處理方式。
統一輸入函數
P2 支持 raw_input 和 input 兩個輸入函數,區別在于前者僅能返回 String 類型對象,后者則支持返回數字和字符串兩種數據類型對象,并且當輸入為表達式時,會隱式調用 eval 函數返回其執行結果。顯然的,使用 input 是更加靈活的寫法。
所以 P3 統一的使用了 input 函數進行輸入處理。
兼容技巧:
統一使用 input 內置函數。
1
2
3
4
5
input("Type something safe please: ")
Python 2 and 3from future.builtins import input
eval(input("Type something safe please: "))
統一輸出函數
P2 中的 print 即是關鍵字又是內置函數。print "Hello world!" 為一條語句,print("Hello world!") 則為一次函數調用。
P3 統一使用 print 函數進行輸出操作,其原型如下,這一改變讓 P3 的輸出處理變得更加簡潔、強大而優雅,通過實參的傳遞就能替代 P2 中繁復的代碼實現。
1
print(*objects, sep=" ", end="n", file=sys.stdout, flush=False)
兼容技巧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
print "Hello"
Python 2 only:print "Hello"
單行打印多個 String Python 2 only:print "Hello", "Guido"
Python 2 and 3:from future import print_function # (at top of module)
print("Hello", "Guido")
print >> sys.stderr, "Hello"
Python 2 and 3:from future import print_function
print("Hello", file=sys.stderr)
print "Hello",
Python 2 and 3:from future import print_function
print("Hello", end="")
統一文件操作函數
P2 支持使用 file 和 open 兩個函數來進行文件操作。
P3 則統一使用 open 來進行文件操作。
兼容技巧:
統一使用 open 函數。
1
2
3
4
f = file(pathname)
Python 2 and 3:f = open(pathname)
統一列表迭代器生成函數
P2 支持使用 range 和 xrange 兩個函數來生成可迭代對象,區別在于前者返回的是一個列表類型對象,后者返回的是一個類似生成器(惰性求值)的迭代對象,支持無限迭代。所以當你需要生成一個很大的序列時,推薦使用 xrange,因為它不會一上來就索取序列所需的所有內存空間。如果只對序列進行讀操作的話,xrange 方法效率顯然會更高,但是如果要修改序列的元素,或者往序列增刪元素的話,那只能通過 range 方法生成一個 list 對象了。
P3 則統一使用 range 函數來生成可迭代對象,但其實 P3 的 range 更像是 P2 的 xrange。所以在 P3 中如果你想得到一個可以被修改的列表對象,你需要這么做:
1
2
list(range(1,10))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
兼容技巧:
統一使用 range 函數
1
2
3
4
5
6
7
8
9
10
11
for i in xrange(10**8):
...Python 2 and 3: forward-compatible
from future.builtins import range
for i in range(10**8):
...Python 2 and 3: backward-compatible
from past.builtins import xrange
for i in xrange(10**8):
...
統一迭代器迭代函數
P2 中支持使用內置函數 next 和迭代器對象的 .next() 實例方法這兩種方式來獲取迭代器對象的下一個元素。所以,在實現自定義迭代器對象類時,必須實現 .next() 實例方法:
1
2
3
4
5
6
7
8
9
10
11
class Upper(object):
def __init__(self, iterable): self._iter = iter(iterable) def next(self): # Py2-styface iterator interface return self._iter.next().upper() def __iter__(self): return self
itr = Upper("hello")
assert itr.next() == "H" # Py2-style
assert list(itr) == list("ELLO")
但在 P3 中統一了使用 next 內置函數來獲取下一個元素,如果試圖調用 .next() 方法則會觸發 AttributeError 異常。所以,在 P3 中實現自定義迭代器所要實現的是 next 特殊方法。
兼容技巧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from future.builtins import object
class Upper(object):
def __init__(self, iterable): self._iter = iter(iterable) def __next__(self): # Py3-style iterator interface return next(self._iter).upper() # builtin next() function calls def __iter__(self): return self
itr = Upper("hello")
assert next(itr) == "H" # compatible style
assert list(itr) == list("ELLO")
from future.utils import implements_iterator
@implements_iterator
class Upper(object):
def __init__(self, iterable): self._iter = iter(iterable) def __next__(self): # Py3-style iterator interface return next(self._iter).upper() # builtin next() function calls def __iter__(self): return self
itr = Upper("hello")
assert next(itr) == "H"
assert list(itr) == list("ELLO")
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43311.html
摘要:可是當我測試,我就懵逼了,中文真都驗證通過,不對啊,我以前也是這么過濾參數的,測試沒問題啊唯一的區別是現在用的是。 上周,我的測試同事告訴我,你的用戶名怎么還允許中文啊?當時我心里就想,你們測試肯定又搞錯接口了,我用的是正則w過濾了參數,怎么可能出錯,除非Python正則系統出錯了,那是不可能的。本著嚴謹的作風,我自己先測試一下,沒問題看我怎么懟回去。可是當我測試,我就懵逼了,中文真T...
摘要:認為有極大的優化空間,在字符串和整形操作上可以取得很好的優化結果。的和方法返回迭代器,而之前的等函數都被廢棄。python有兩個主要的版本,python2 和 python3 ,但是python又不同于其他語言,向下兼容,python3是不向下兼容的,但是絕大多數組件和擴展都是基于python2的,下面就來總結一下python2和python3的區別。 ? 1.性能? Py3.0運...
摘要:認為有極大的優化空間,在字符串和整形操作上可以取得很好的優化結果。的和方法返回迭代器,而之前的等函數都被廢棄。python有兩個主要的版本,python2 和 python3 ,但是python又不同于其他語言,向下兼容,python3是不向下兼容的,但是絕大多數組件和擴展都是基于python2的,下面就來總結一下python2和python3的區別。 ? 1.性能? Py3.0運...
摘要:年月宣布支持時間延長到年。更詳細的發布列表參閱官網的版本號分為三段,形如。其中表示大版本號,一般當整體重寫,或出現不向后兼容的改變時,增加表示功能更新,出現新功能時增加表示小的改動如修復了某個,只要有修改就增加。年公司正式發布。 < 返回索引頁 Python語言簡介 Python介紹及發展 介紹 Python 官方網站:https://www.python.org/, 大家可以到此處下...
摘要:可是當我測試,我就懵逼了,中文真都驗證通過,不對啊,我以前也是這么過濾參數的,測試沒問題啊唯一的區別是現在用的是。 發現問題 上周,我的測試同事告訴我,你的用戶名怎么還允許中文啊?當時我心里就想,你們測試肯定又搞錯接口了,我用的是正則w過濾了參數,怎么可能出錯,除非Python正則系統出錯了,那是不可能的。本著嚴謹的作風,我自己先測試一下,沒問題看我怎么懟回去。可是當我測試,我就懵逼了...
閱讀 1554·2021-11-19 09:55
閱讀 2778·2021-09-06 15:02
閱讀 3534·2019-08-30 15:53
閱讀 1071·2019-08-29 16:36
閱讀 1230·2019-08-29 16:29
閱讀 2286·2019-08-29 15:21
閱讀 621·2019-08-29 13:45
閱讀 2679·2019-08-26 17:15