【python】如何寫出兼容py2與py3的代碼

問題

Python2已經停止維護,但由於歷史原因,我們不得不在接下來的幾年中,習慣兩種語言依然共存的狀況。
如果能習慣性地寫出同時兼容py2與py3的代碼,就可以減少很多不必要的踩坑。

前言

博主研一時用py2,研二後改用py2。
現在工作了,每次都要在本地寫適配py3的代碼,放到只能適配py2的服務器上去跑。對於如何寫出兼容py2與py3的代碼,積累了一點踩坑心得。

下文是我總結的一些個人經驗。如有概括不全或描述不當的地方,懇請指出~

print

這個是最明顯的了。

py版本 可接受的寫法
2.x print( xxx )、print xxx、print xxx xxx
3.x print( xxx )、print( xxx, xxx )

取交集,建議日常遵從如下寫法:

print( xxx )

數值計算

  1. __future__模塊的使用,可以在py2中調用py3的某些功能:

    from __future__ import print_function
    from __future__ import unicode_literals
    from __future__ import division
    from __future__ import absolute_import
    
  2. 除號
    /” 在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的代碼 }

結語

先想到這麼多,後面想起來再持續補充 ~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章