問題
Python2已經停止維護,但由於歷史原因,我們不得不在接下來的幾年中,習慣兩種語言依然共存的狀況。
如果能習慣性地寫出同時兼容py2與py3的代碼,就可以減少很多不必要的踩坑。
前言
博主研一時用py2,研二後改用py2。
現在工作了,每次都要在本地寫適配py3的代碼,放到只能適配py2的服務器上去跑。對於如何寫出兼容py2與py3的代碼,積累了一點踩坑心得。
下文是我總結的一些個人經驗。如有概括不全或描述不當的地方,懇請指出~
這個是最明顯的了。
py版本 | 可接受的寫法 |
---|---|
2.x | print( xxx )、print xxx、print xxx xxx |
3.x | print( xxx )、print( xxx, xxx ) |
取交集,建議日常遵從如下寫法:
print( xxx )
數值計算
-
__future__
模塊的使用,可以在py2中調用py3的某些功能:from __future__ import print_function from __future__ import unicode_literals from __future__ import division from __future__ import absolute_import
-
除號
“/
” 在py3中是精確除法;在py2中只有浮點除時才爲精確除,否則爲地板除。
如果想用 “精確除” ,就老老實實確保被除數或者除數是絕對的浮點型:res = float( {被除數} ) / {除數}
如果想用 “地板除” ,就老老實實用 “
//
”。
路徑
__file__
在py3下返回文件 絕對地址,在py2下則返回 相對地址 。
想確保在任何py版本下獲取的都是絕對地址,可以藉助 os.path.abspath()
:
import os
path = os.path.abspath(__file__)
內置函數
很多常見的內置函數(又稱“內建函數”,包括reduce、filter、map等等)在py2下返回的是list,在py3下返回的卻是一個函數對象。
由於 list(list())
效果等同於list()
,而list(函數對象)
可以達到和py3一樣的返回效果,所以建議調用內置函數時儘量採用如下寫法:
res = list( 內置函數的調用 )
另外,reduce()函數已被py3從全局名字空間裏移除了,所以能別用reduce儘量別用,或者用其他函數替換之也可。
導入自定義庫文件
py2默認是按照 相對路徑 導入模塊和包,然而py3卻默認按照 絕對路徑 導入。
- 文件路徑直接在當前工作目錄下(即
os.path.dirname(os.path.abspath(__file__)) == os.getcwd()
)時:py2和py3都可以通過如下方式來導入相同目錄下的庫文件:import util
- 文件路徑不直接在當前工作目錄下時:py3導入相同目錄下的庫文件就不能再那麼寫了,而是要改一下:
if sys.version_info.major >= 3 and os.path.dirname(os.path.abspath(__file__)) != os.getcwd(): from . import util else: import util
一些常見的api
os
用於創建遞歸目錄樹的 os.makedirs({文件夾名}, exist_ok=True)
中,exist_ok
參數是py3.2才加入的,所以建議使用如下寫法:
try:
os.makedirs({文件夾名})
except:
pass
這樣同樣可以達到“遞歸建立一個不存在的文件夾,如果存在則跳過”的效果。
其他trick
預判py版本
if sys.version_info.major >= 3: // 如果當前編譯器版本是3.x
{ 執行適配py3的代碼 }
else:
{ 執行適配py2的代碼 }
結語
先想到這麼多,後面想起來再持續補充 ~