Python2與Python3兼容


Python2與Python3兼容

python3寫的代碼如何也能在pyhon2上跑?請無論如何加上這一句,python3沒有啥影響

from __future__ import absolute_import, unicode_literals, division, print_function

__future__模塊提供某些將要引入的特性,python 2.7.5的__future__基本上是python3中的特性

開始

使用我們的jupyter交互式工具進行探討,以下皆為python2

有以下內容

In [1]: import __future__

In [2]: __future__.
__future__.CO_FUTURE_ABSOLUTE_IMPORT  __future__.all_feature_names
__future__.CO_FUTURE_DIVISION         __future__.division
__future__.CO_FUTURE_PRINT_FUNCTION   __future__.generators
__future__.CO_FUTURE_UNICODE_LITERALS __future__.nested_scopes
__future__.CO_FUTURE_WITH_STATEMENT   __future__.print_function
__future__.CO_GENERATOR_ALLOWED       __future__.unicode_literals
__future__.CO_NESTED                  __future__.with_statement
__future__.absolute_import

In [2]: __future__.

可導入的功能有哪些?

In [3]: import __future__

In [4]: __future__.all_feature_names
Out[4]:
['nested_scopes',
 'generators',
 'division',
 'absolute_import',
 'with_statement',
 'print_function',
 'unicode_literals']

對應功能如下

division

division 新的除法特性,本來的除號/對於分子分母是整數的情況會取整,但新特性中在此情況下的除法不會取整,取整的使用//。如下可見,只有分子分母都是整數時結果不同。

In [1]: 3 / 5
Out[1]: 0

In [2]: 3 // 5
Out[2]: 0

In [3]: 3.0 / 5.0
Out[3]: 0.6

In [4]: 3.0 // 5.0
Out[4]: 0.0

In [5]: from __future__ import division

In [6]: 3 / 5
Out[6]: 0.6

In [7]: 3 // 5
Out[7]: 0

In [8]: 3.0 / 5.0
Out[8]: 0.6

In [9]: 3.0 // 5.0
Out[9]: 0.0

print_function 新的print是一個函數,如果導入此特性,之前的print語句就不能用了。

In [1]: print 'test __future__'
test __future__

In [2]: from __future__ import print_function

In [3]: print('test')
test

In [4]: print 'test'
  File "<ipython-input-4-ed4b06bfff9f>", line 1
    print 'test'
               ^
SyntaxError: invalid syntax

unicode_literals

unicode_literals 這個是對字符串使用unicode字符

In [1]: print '目錄'
鐩綍

In [2]: from __future__ import unicode_literals

In [3]: print '目錄'
目錄

python 2.x中, 對於漢字字符串, 默認還不是采用unicode編碼的, 除非在字符串前加上前綴u. 比如:

x='中國' 
x 
'\xd6\xd0\xb9\xfa'   這不是unicode編碼
print(x) 
中國 
x=u'中國' 
u'\u4e2d\u56fd' 
print(x) 
中國

python3中默認的編碼采用了unicode, 並取消了前綴u. 如果代碼要兼容python2/3, 就很麻煩了. 下面的兩個選擇都不方便:

  1. 字符串前面不加u. 這種處理方式多數情況下沒有問題, 比如print輸出, 但因為漢字在py2和py3的編碼方式不一樣, 如果進行編碼轉換就麻煩了.
  2. python版本判斷, if sys.version < '3', 字符串不加前綴u, 如果是py2, 加上前綴u. 這樣代碼顯得很拖沓.
  3. 現在有第3種, 比較好的方法是引入unicode_literals, from __future__ import unicode_literals , 這樣在py2下, '中國'這樣的字符串不用家前綴u, 也是unicode編碼.

absolute_import

字面理解好像是僅僅允許絕對引用, 其實不然, 真實意思是禁用隱式相對引用:implicit relative import, 但並不會禁掉顯式相對引用:explicit relative import.

舉個例子, 目錄結構如下,

-cake
|- __init__.py
|- icing.py
|- sponge.py
-drink
|- __init__.py
|- water.py

sponge.py 引用 icing , 有多種方法:

  1. import icing隱式相對引用, py2已強烈不推薦使用, py3已經不可用了
  2. from . import icing顯式相對引用, python.org 官方雖不推薦, 但這卻是事實標准
  3. from cake import icing絕對引用 , python 官方推薦.

使用 __future__ absolute_import之后, 常遇到的一個問題

PackageA
|- module1.py
|- module2.py
|- __init__.py 

在module1.py中, 
from __future__ import absolute_impact
from . import module2 #引入同包下的另一個module

if __name__=="__main__":
print("module2 was imported in module1.")

運行會報錯, ValueError: Attempted relative import in non-package.

原因分析: from . import module2 這樣的寫法是顯式相對引用, 這種引用方式只能用於package中, 而不能用於主模塊中.
因為主modulename總是為main, 並沒有層次結構, 也就無從談起相對引用了.
換句話, if __name__=="__main__": 和相對引用是不能並存的.

解決方法:

  1. module1中使用絕對引用, 這個最簡單了, 但相對引用的好處也沒了.
  2. 使用python -m來啟動你的module1.py, 這個也不推薦.
  3. (推薦,我覺得還是和第一個差不多,只不過測試換在了另外的地方)在module1中, 加個main()函數, 然后再新建一個PackageA/entry.py做為主程序, 在entry.py中使用絕對引用來引用module1, 並調用module1.main(), 這一辦法雖不完美, 但我覺得是最好的方法了.

nested_scopes

這個是修改嵌套函數或lambda函數中變量的搜索順序,從當前函數命名空間->模塊命名空間的順序更改為了當前函數命名空間->父函數命名空間->模塊命名空間,python2.7.5中默認使用

generators

生成器,對應yield的語法,python2.7.5中默認使用

with_statement

使用with關鍵字,python2.7.5是默認使用

運用

首先是可以做個性化的用法,比如你喜歡用print()而不是print

更重要的是基本用以下幾句就可以讓python2和python3有良好的兼容性了

from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division
from __future__ import absolute_import


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM