將 Python 2 代碼遷移到 Python 3?
- 作者
Brett Cannon
摘要
Python 3 是 Python 的未來(lái),但 Python 2 仍處于活躍使用階段,最好讓您的項(xiàng)目在兩個(gè)主要版本的Python 上都可用。本指南旨在幫助您了解如何最好地同時(shí)支持 Python 2 和 3。
如果您希望遷移擴(kuò)展模塊而不是純 Python 代碼,請(qǐng)參閱 將擴(kuò)展模塊移植到 Python 3。
如果你想了解核心 Python 開發(fā)者對(duì)于 Python 3 的出現(xiàn)有何看法,你可以閱讀 Nick Coghlan 的 Python 3 Q & A 或 Brett Cannon 的 為什么要有 Python 3.
關(guān)于遷移的幫助,你可以查看存檔的 python-porting 郵件列表。
簡(jiǎn)要說(shuō)明?
為了使你的項(xiàng)目以一份源代碼與Python 2/3兼容,基本步驟如下:
只擔(dān)心支持Python 2.7的問(wèn)題
確保你有良好的測(cè)試覆蓋率(可以用 coverage.py;
python -m pip install coverage
)。了解Python 2 和 3之間的區(qū)別
使用 Futurize (或Modernize) 來(lái)更新你的代碼 (例如``python -m pip install future``)。
使用 Pylint 來(lái)幫助確保你在Python 3支持上不倒退(
python -m pip install pylint
)使用 caniusepython3 來(lái)找出你的哪些依賴關(guān)系阻礙了你對(duì) Python 3 的使用 (
python -m pip install caniusepython3
)一旦你的依賴性不再阻礙你,使用持續(xù)集成來(lái)確保你與 Python 2 和 3 保持兼容 (tox 可以幫助對(duì)多個(gè)版本的 Python 進(jìn)行測(cè)試;
python -m pip install tox
)考慮使用可選的靜態(tài)類型檢查,以確保你的類型用法在 Python 2 和 3 中都適用 (例如,使用 mypy 來(lái)檢查你在 Python 2 和 Python 3 中的類型;
python -m pip install mypy
)。
備注
注意:使用 python -m pip install
來(lái)確保你發(fā)起調(diào)用的 pip
就是當(dāng)前使用的 Python 所安裝的那一個(gè),無(wú)論它是系統(tǒng)級(jí)的 pip
還是安裝在 虛擬環(huán)境 中的。
詳情?
同時(shí)支持Python 2和3的一個(gè)關(guān)鍵點(diǎn)是,你可以從**今天**開始!即使你的依賴關(guān)系還不支持Python 3,也不意味著你不能現(xiàn)在就對(duì)你的代碼進(jìn)行現(xiàn)代化改造以支持Python 3。支持Python 3所需的大多數(shù)變化都會(huì)使代碼更干凈,甚至在Python 2的代碼中也會(huì)使用更新的做法。
另一個(gè)關(guān)鍵點(diǎn)是,使你的Python 2代碼現(xiàn)代化以支持Python 3在很大程度上是為你自動(dòng)化的。雖然由于Python 3清晰區(qū)分了文本數(shù)據(jù)與二進(jìn)制數(shù)據(jù),你可能必須做出一些API決定。但現(xiàn)在已經(jīng)為你完成了大部分底層的工作,因此至少可以立即從自動(dòng)化變化中受益。
當(dāng)你繼續(xù)閱讀關(guān)于遷移你的代碼以同時(shí)支持Python 2和3的細(xì)節(jié)時(shí),請(qǐng)牢記這些關(guān)鍵點(diǎn)。
刪除對(duì)Python 2.6及更早版本的支持?
雖然你可以讓 Python 2.5 與 Python 3 一起工作,但如果你只需要與 Python 2.7 一起工作,那就會(huì) 更加容易。 如果放棄 Python 2.5 不是一種選擇,那么 six 項(xiàng)目可以幫助你同時(shí)支持 Python 2.5 和 3 (python -m pip install six
)。 不過(guò)請(qǐng)注意,本 HOWTO 中列出的幾乎所有項(xiàng)目都有可能會(huì)不再可用。
如果你能夠跳過(guò)Python 2.5和更早的版本,那么對(duì)你的代碼所做的必要修改應(yīng)該看起來(lái)和感覺(jué)上都是你已經(jīng)習(xí)慣的Python代碼。在最壞的情況下,你將不得不使用一個(gè)函數(shù)而不是一個(gè)實(shí)例方法,或者不得不導(dǎo)入一個(gè)函數(shù)而不是使用一個(gè)內(nèi)置的函數(shù),但除此之外,整體的轉(zhuǎn)變應(yīng)該不會(huì)讓你感到陌生。
但你的目標(biāo)應(yīng)該是只支持 Python 2.7。Python 2.6 不再被免費(fèi)支持,因此也就沒(méi)有得到錯(cuò)誤修復(fù)。這意味著**你**必須解決你在Python 2.6上遇到的任何問(wèn)題。本HOWTO中提到的一些工具也不支持Python 2.6 (例如,Pylint),隨著時(shí)間的推移,這將變得越來(lái)越普遍。如果你只支持你必須支持的Python版本,那么對(duì)你來(lái)說(shuō)會(huì)更容易。
確保你在你的``setup.py``文件中指定適當(dāng)?shù)陌姹局С?a title="永久鏈接至標(biāo)題" class="headerlink" href="#make-sure-you-specify-the-proper-version-support-in-your-setup-py-file">?
在你的``setup.py``文件中,你應(yīng)該有適當(dāng)?shù)?trove classifier 指定你支持哪些版本的 Python。由于你的項(xiàng)目還不支持 Python 3,你至少應(yīng)該指定``Programming Language :: Python :: 2 :: Only``。理想情況下,你還應(yīng)該指定你所支持的Python的每個(gè)主要/次要版本,例如:Programming Language :: Python :: 2.7
。.
良好的測(cè)試覆蓋率?
一旦你的代碼支持了你希望的Python 2的最老版本,你將希望確保你的測(cè)試套件有良好的覆蓋率。一個(gè)好的經(jīng)驗(yàn)法則是,如果你想對(duì)你的測(cè)試套件有足夠的信心,在讓工具重寫你的代碼后出現(xiàn)的任何故障都是工具中的實(shí)際錯(cuò)誤,而不是你的代碼中的錯(cuò)誤。如果你想要一個(gè)目標(biāo)數(shù)字,試著獲得超過(guò)80%的覆蓋率(如果你發(fā)現(xiàn)很難獲得好于90%的覆蓋率,也不要感到遺憾)。如果你還沒(méi)有一個(gè)測(cè)量測(cè)試覆蓋率的工具,那么推薦使用coverage.py。
了解Python 2 和 3之間的區(qū)別?
一旦你的代碼經(jīng)過(guò)了很好的測(cè)試,你就可以開始把你的代碼移植到 Python 3 上了! 但是為了充分了解你的代碼將發(fā)生怎樣的變化,以及你在編碼時(shí)要注意什么,你將會(huì)想要了解 Python 3 相比 Python 2 的變化。 通常來(lái)說(shuō),兩個(gè)最好的方法是閱讀 Python 3 每個(gè)版本的 "What's New" 文檔和 Porting to Python 3 書(在線免費(fèi)版本)。還有一個(gè)來(lái)自 Python-Future 項(xiàng)目的便利 cheat sheet。
更新代碼?
一旦你覺(jué)得你知道了 Python 3 與 Python 2 相比有什么不同,就是時(shí)候更新你的代碼了! 你可以選擇兩種工具來(lái)自動(dòng)移植你的代碼: Futurize 和 Modernize。 你選擇哪個(gè)工具將取決于你希望你的代碼有多像 Python 3。 Futurize 盡力使 Python 3 的習(xí)性和做法在 Python 2 中存在,例如,從 Python 3 中回傳 bytes
類型,這樣你就可以在 Python 的主要版本之間實(shí)現(xiàn)語(yǔ)義上的平等。 另一方面,Modernize 更加保守,它針對(duì)的是 Python 2/3 的子集,直接依靠 six 來(lái)幫助提供兼容性。 由于 Python 3 是未來(lái),最好考慮 Futurize,以開始適應(yīng) Python 3 所引入的、你還不習(xí)慣的任何新做法。
無(wú)論你選擇哪種工具,它們都會(huì)更新你的代碼,使之在Python 3下運(yùn)行,同時(shí)與你開始使用的Python 2版本保持兼容。根據(jù)你想要的保守程度,你可能想先在你的測(cè)試套件上運(yùn)行該工具,并目測(cè)差異以確保轉(zhuǎn)換的準(zhǔn)確性。在你轉(zhuǎn)換了你的測(cè)試套件并驗(yàn)證了所有的測(cè)試仍然如期通過(guò)后,你就可以轉(zhuǎn)換你的應(yīng)用程序代碼了,因?yàn)槟阒廊魏螠y(cè)試失敗都是轉(zhuǎn)譯的錯(cuò)誤。
不幸的是,這些工具不能自動(dòng)地使你的代碼在Python 3下工作,因此有一些東西你需要手動(dòng)更新以獲得對(duì)Python 3的完全支持(這些步驟在不同的工具中是必要的)。閱讀你選擇使用的工具的文檔,看看它默認(rèn)修復(fù)了什么,以及它可以選擇做什么,以了解哪些將(不)為你修復(fù),哪些你可能必須自己修復(fù)(例如,在Modernize中使用``io.open()``覆寫內(nèi)置的``open()``函數(shù)默認(rèn)是關(guān)閉的)。不過(guò)幸運(yùn)的是,只有幾件需要注意的事情,可以說(shuō)是大問(wèn)題,如果不注意的話,可能很難調(diào)試。
除法?
在Python 3中,5 / 2 == 2.5``而不是``2
;所有``int``數(shù)值之間的除法都會(huì)產(chǎn)生一個(gè)``float``、這個(gè)變化實(shí)際上從2002年發(fā)布的Python 2.2開始就已經(jīng)計(jì)劃好了。從那時(shí)起,我們就鼓勵(lì)用戶在所有使用``/和
//運(yùn)算符的文件中添加``from __future__ import division
,或者在運(yùn)行解釋器時(shí)使用``-Q``標(biāo)志。如果你沒(méi)有這樣做,那么你需要檢查你的代碼并做兩件事。
添加
from __future__ import division
到你的文件。根據(jù)需要更新任何除法運(yùn)算符,要么使用
//
來(lái)使用向下取整除法,要么繼續(xù)使用/
并得到一個(gè)浮點(diǎn)數(shù)
之所以沒(méi)有簡(jiǎn)單地將 /
自動(dòng)翻譯成 //
,是因?yàn)槿绻粋€(gè)對(duì)象定義了一個(gè) __truediv__
方法,但沒(méi)有定義 __floordiv__
,那么你的代碼就會(huì)運(yùn)行失敗(例如,一個(gè)用戶定義的類用 /
來(lái)表示一些操作,但沒(méi)有用 //
來(lái)表示同樣的事情或根本沒(méi)有定義)。
文本與二進(jìn)制數(shù)據(jù)?
在Python 2中,你可以對(duì)文本和二進(jìn)制數(shù)據(jù)都使用``str``類型。不幸的是,這兩個(gè)不同概念的融合可能會(huì)導(dǎo)致脆弱的代碼,有時(shí)對(duì)任何一種數(shù)據(jù)都有效,有時(shí)則無(wú)效。如果人們沒(méi)有明確說(shuō)明某種接受``str``東西可以接受文本或二進(jìn)制數(shù)據(jù),而不是一種特定的類型,這也會(huì)導(dǎo)致API的混亂。這使情況變得復(fù)雜,特別是對(duì)于任何支持多種語(yǔ)言的人來(lái)說(shuō),因?yàn)锳PI在聲稱支持文本數(shù)據(jù)時(shí)不會(huì)顯式支持``unicode``。
為了使文本和二進(jìn)制數(shù)據(jù)之間的區(qū)別更加清晰和明顯,Python 3做了大多數(shù)在互聯(lián)網(wǎng)時(shí)代創(chuàng)建的語(yǔ)言所做的事情,使文本和二進(jìn)制數(shù)據(jù)成為不能盲目混合在一起的不同類型(Python早于互聯(lián)網(wǎng)的廣泛使用)。對(duì)于任何只處理文本或只處理二進(jìn)制數(shù)據(jù)的代碼,這種分離并不構(gòu)成問(wèn)題。但是對(duì)于必須處理這兩種數(shù)據(jù)的代碼來(lái)說(shuō),這確實(shí)意味著你現(xiàn)在可能必須關(guān)心你何時(shí)使用文本或二進(jìn)制數(shù)據(jù),這就是為什么這不能完全自動(dòng)化遷移。
首先,你需要決定哪些 API 接受文本,哪些接受二進(jìn)制(由于保持代碼工作的難度,強(qiáng)烈 建議你不要設(shè)計(jì)同時(shí)接受兩種數(shù)據(jù)的 API;如前所述,這很難做得好)。在 Python 2 中,這意味著要確保處理文本的 API 能夠與 unicode
一起工作,而處理二進(jìn)制數(shù)據(jù)的 API 能夠與 Python 3 中的 bytes
類型一起工作(在 Python 2 中是 str
的一個(gè)子集,在 Python 2 中作為 bytes
類型的別名)。通常最大的問(wèn)題是意識(shí)到哪些方法同時(shí)存在于 Python 2 和 3 的哪些類型上 (對(duì)于文本來(lái)說(shuō),Python 2 中是 unicode
,Python 3 中是 str
,對(duì)于二進(jìn)制來(lái)說(shuō),Python 2 中是 str
/bytes
,Python 3 中是``bytes``)。 下表列出了每個(gè)數(shù)據(jù)類型在 Python 2 和 3 中的 獨(dú)特 的方法 (例如,decode()
方法在 Python 2 或 3 中的等價(jià)二進(jìn)制數(shù)據(jù)類型上是可用的,但是它不能在 Python 2 和 3 之間被文本數(shù)據(jù)類型一致使用,因?yàn)?Python 3 中的 str
沒(méi)有這個(gè)方法)。 請(qǐng)注意,從 Python 3.5 開始,__mod__
方法被添加到 bytes 類型中。
文本數(shù)據(jù) |
二進(jìn)制數(shù)據(jù) |
decode |
|
encode |
|
format |
|
isdecimal |
|
isnumeric |
通過(guò)在你的代碼邊緣對(duì)二進(jìn)制數(shù)據(jù)和文本進(jìn)行編碼和解碼,可以使這種區(qū)分更容易處理。這意味著,當(dāng)你收到二進(jìn)制數(shù)據(jù)的文本時(shí),你應(yīng)該立即對(duì)其進(jìn)行解碼。而如果你的代碼需要將文本作為二進(jìn)制數(shù)據(jù)發(fā)送,那么就盡可能晚地對(duì)其進(jìn)行編碼。這使得你的代碼在內(nèi)部只與文本打交道,從而不必再去跟蹤你所處理的數(shù)據(jù)類型。
下一個(gè)問(wèn)題是確保你知道你的代碼中的字符串字頭是代表文本還是二進(jìn)制數(shù)據(jù)。你應(yīng)該給任何呈現(xiàn)二進(jìn)制數(shù)據(jù)的字面符號(hào)添加一個(gè)``b``前綴。對(duì)于文本,你應(yīng)該給文本字面添加一個(gè)``u``前綴。(有一個(gè) __future__
導(dǎo)入來(lái)強(qiáng)制所有未指定的字頭為Unicode,但實(shí)際使用情況表明它并不像給所有字頭顯式添加一個(gè)``b``或``u``前綴那樣有效)
作為這種二分法的一部分,你還需要小心打開文件。除非你一直在 Windows 上工作,否則你有可能在打開二進(jìn)制文件時(shí)沒(méi)有一直費(fèi)心地添加``b``模式 (例如,用``rb``進(jìn)行二進(jìn)制讀取)。 在 Python 3 下,二進(jìn)制文件和文本文件顯然是不同的,而且是相互不兼容的;詳見 io
模塊。因此,你必須**決定**一個(gè)文件是用于二進(jìn)制訪問(wèn)(允許讀取和/或?qū)懭攵M(jìn)制數(shù)據(jù))還是文本訪問(wèn)(允許讀取和/或?qū)懭胛谋緮?shù)據(jù))。你還應(yīng)該使用 io.open()
來(lái)打開文件,而不是內(nèi)置的 open()
函數(shù),因?yàn)?io
模塊從 Python 2 到 3 是一致的,而內(nèi)置的 open()
函數(shù)則不是 (在 Python 3 中它實(shí)際上是 io.open()
)。不要理會(huì)使用 codecs.open()
的過(guò)時(shí)做法,因?yàn)檫@只是為了保持與 Python 2.5 的兼容性。
在Python 2和3中,str``和``bytes``的構(gòu)造函數(shù)對(duì)相同的參數(shù)有不同的語(yǔ)義。在Python 2中,傳遞一個(gè)整數(shù)給``bytes
,你將得到整數(shù)的字符串表示:bytes(3) == '3'
。但是在Python 3中,一個(gè)整數(shù)參數(shù)傳遞給``bytes``將給你一個(gè)與指定的整數(shù)一樣長(zhǎng)的bytes對(duì)象,其中充滿了空字節(jié):bytes(3) == b'\x00\x00\x00'
。當(dāng)把bytes對(duì)象傳給``str``時(shí),類似的擔(dān)心是必要的。 在Python 2中,你只是又得到了該bytes對(duì)象:str(b'3') == b'3'
。但是在Python 3中,你得到bytes對(duì)象的字符串表示:str(b'3') == "b'3'"
。
最后,二進(jìn)制數(shù)據(jù)的索引需要仔細(xì)處理(切片 不需要 任何特殊處理)。在 Python 2 中 b'123'[1] == b'2'
,而在 Python 3 中``b'123'[1] == 50``。 因?yàn)槎M(jìn)制數(shù)據(jù)只是二進(jìn)制數(shù)的集合,Python 3 會(huì)返回你索引的字節(jié)的整數(shù)值。 但是在 Python 2 中,因?yàn)?bytes == str
,索引會(huì)返回一個(gè)單項(xiàng)的字節(jié)片斷。 six 項(xiàng)目有一個(gè)名為 six.indexbytes()
的函數(shù),它將像在 Python 3 中一樣返回一個(gè)整數(shù): six.indexbytes(b'123', 1)
。
總結(jié)一下:
決定你的API中哪些采用文本,哪些采用二進(jìn)制數(shù)據(jù)
確保你對(duì)文本工作的代碼也能對(duì)``unicode``工作,對(duì)二進(jìn)制數(shù)據(jù)的代碼在Python 2中能對(duì)``bytes``工作(關(guān)于每種類型不能使用的方法,見上表)。
用``b``前綴標(biāo)記所有二進(jìn)制字詞,用``u``前綴標(biāo)記文本字詞
盡快將二進(jìn)制數(shù)據(jù)解碼為文本,盡可能晚地將文本編碼為二進(jìn)制數(shù)據(jù)
使用
io.open()
打開文件,并確保在適當(dāng)時(shí)候指定b
模式。在對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行索引時(shí)要小心
使用特征檢測(cè)而不是版本檢測(cè)?
你不可避免地會(huì)有一些代碼需要根據(jù)運(yùn)行的 Python 版本來(lái)選擇要做什么。做到這一點(diǎn)的最好方法是對(duì)你運(yùn)行的 Python 版本是否支持你所需要的東西進(jìn)行特征檢測(cè)。如果由于某種原因這不起作用,那么你應(yīng)該讓版本檢測(cè)針對(duì) Python 2 而不是 Python 3。為了幫助解釋這個(gè)問(wèn)題,讓我們看一個(gè)例子。
假設(shè)你需要訪問(wèn) importlib
的一個(gè)功能,該功能自Python 3.3開始在Python的標(biāo)準(zhǔn)庫(kù)中提供,并且通過(guò)PyPI上的 importlib2 提供給Python 2。你可能會(huì)想寫代碼來(lái)訪問(wèn)例如 importlib.abc
模塊,方法如下:
import sys
if sys.version_info[0] == 3:
from importlib import abc
else:
from importlib2 import abc
這段代碼的問(wèn)題是,當(dāng)Python 4出來(lái)的時(shí)候會(huì)發(fā)生什么?最好是將Python 2作為例外情況,而不是Python 3,并假設(shè)未來(lái)的Python版本與Python 3的兼容性比Python 2更強(qiáng):
import sys
if sys.version_info[0] > 2:
from importlib import abc
else:
from importlib2 import abc
不過(guò),最好的解決辦法是根本不做版本檢測(cè),而是依靠特征檢測(cè)。這就避免了任何潛在的版本檢測(cè)錯(cuò)誤的問(wèn)題,并有助于保持你對(duì)未來(lái)的兼容:
try:
from importlib import abc
except ImportError:
from importlib2 import abc
防止兼容性退步?
一旦你完全翻譯了你的代碼,使之與 Python 3 兼容,你將希望確保你的代碼不會(huì)退步,不會(huì)在 Python 3上停止工作。如果你有一個(gè)依賴關(guān)系阻礙了你目前在Python 3上的實(shí)際運(yùn)行,那就更是如此了。
為了幫助保持兼容,你創(chuàng)建的任何新模塊都應(yīng)該在其頂部至少有以下代碼塊:
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
你也可以在運(yùn)行Python 2時(shí)使用``-3``標(biāo)志,對(duì)你的代碼在執(zhí)行過(guò)程中引發(fā)的各種兼容性問(wèn)題進(jìn)行警告。如果你用``-Werror``把警告變成錯(cuò)誤,那么你可以確保你不會(huì)意外地錯(cuò)過(guò)一個(gè)警告。
你也可以使用 Pylint 項(xiàng)目和它的``--py3k``標(biāo)志來(lái)提示你的代碼,當(dāng)你的代碼開始偏離 Python 3 的兼容性時(shí),就會(huì)收到警告。這也避免了你不得不定期在你的代碼上運(yùn)行 Modernize 或 Futurize 來(lái)捕捉兼容性的退步。這確實(shí)要求你只支持Python 2.7和Python 3.4或更新的版本,因?yàn)檫@是Pylint支持的最小Python版本。
檢查哪些依賴性會(huì)阻礙你的過(guò)渡?
在你使你的代碼與 Python 3 兼容**之后**,你應(yīng)該開始關(guān)心你的依賴關(guān)系是否也被移植了。 caniusepython3 項(xiàng)目的建立是為了幫助你確定哪些項(xiàng)目——直接或間接地——阻礙了你對(duì)Python 3的支持。它既有一個(gè)命令行工具,也有一個(gè)在 https://caniusepython3.com 的網(wǎng)頁(yè)界面。
該項(xiàng)目還提供了一些代碼,你可以將其集成到你的測(cè)試套件中,這樣,當(dāng)你不再有依賴關(guān)系阻礙你使用Python 3時(shí),你將有一個(gè)失敗的測(cè)試。這使你不必手動(dòng)檢查你的依賴性,并在你可以開始在Python 3上運(yùn)行時(shí)迅速得到通知。
更新你的``setup.py``文件以表示對(duì)Python 3的兼容?
一旦你的代碼在 Python 3 下工作,你應(yīng)該更新你``setup.py``中的分類器,使其包含``Programming Language :: Python :: 3``并不指定單獨(dú)的 Python 2 支持。這將告訴使用你的代碼的人,你支持Python 2 和 3。理想情況下,你也希望為你現(xiàn)在支持的Python的每個(gè)主要/次要版本添加分類器。
使用持續(xù)集成以保持兼容?
一旦你能夠完全在Python 3下運(yùn)行,你將希望確保你的代碼總是在Python 2和3下工作。在多個(gè)Python解釋器下運(yùn)行測(cè)試的最好工具可能是 tox 。然后你可以將 tox 與你的持續(xù)集成系統(tǒng)集成,這樣你就不會(huì)意外地破壞對(duì) Python 2 或 3 的支持。
你可能還想在 Python 3 解釋器中使用``-bb``標(biāo)志,以便在你將bytes與string或bytes與int進(jìn)行比較時(shí)觸發(fā)一個(gè)異常(后者從 Python 3.5 開始可用)。默認(rèn)情況下,類型不同的比較只是簡(jiǎn)單地返回``False``,但是如果你在文本/二進(jìn)制數(shù)據(jù)處理或字節(jié)的索引分離中犯了一個(gè)錯(cuò)誤,你就不容易發(fā)現(xiàn)這個(gè)錯(cuò)誤。當(dāng)這些類型的比較發(fā)生時(shí),這個(gè)標(biāo)志會(huì)觸發(fā)一個(gè)異常,使錯(cuò)誤更容易被發(fā)現(xiàn)。
基本上就是這樣了! 在這一點(diǎn)上,你的代碼庫(kù)同時(shí)與 Python 2 和 3 兼容。你的測(cè)試也將被設(shè)置為不會(huì)意外地破壞 Python 2 或 3 的兼容性,無(wú)論你在開發(fā)時(shí)通常在哪個(gè)版本下運(yùn)行測(cè)試。
考慮使用可選的靜態(tài)類型檢查?
另一個(gè)幫助移植你的代碼的方法是在你的代碼上使用靜態(tài)類型檢查器,如 mypy 或 pytype。這些工具可以用來(lái)分析你的代碼,就像它在Python 2下運(yùn)行一樣,然后你可以第二次運(yùn)行這個(gè)工具,就像你的代碼在Python 3下運(yùn)行一樣。通過(guò)像這樣兩次運(yùn)行靜態(tài)類型檢查器,你可以發(fā)現(xiàn)你是否錯(cuò)誤地使用了二進(jìn)制數(shù)據(jù)類型,例如在Python的一個(gè)版本中與另一個(gè)版本相比。如果你在你的代碼中添加了可選的類型提示,你也可以明確說(shuō)明你的API是使用文本數(shù)據(jù)還是二進(jìn)制數(shù)據(jù),這有助于確保在兩個(gè)版本的Python中所有的功能都符合預(yù)期。