是時候把你的Python2應用遷移到Python3了

到2020年一月1日,Python2.7將再也不受到官方維護,小夥伴,程序猿,工程獅們,是時候將大家的Python2遷移到Python3了。由於距這一天只有10個月了!html

許多的開源項目已經準備好離python2而去了:python

上面的列表只是其中一些,包括了許多我經常使用的機器學習的庫,Tensorflow,Pandas,Scikit-learn,Numpy等等,看看有沒有你經常使用的呢?git

Python2 VS Python3

那麼我麼就先來看看Python2/3的主要差別吧。github

Python3引入了不少和Python2不兼容的關鍵字和功能,其中一些能夠經過Python2內置的__future__模塊來實現前向兼容,也就是說可讓你的Python2的代碼在Python3的解釋器中運行。若是你計劃要支持Python3,那麼你能夠在你的Python2的代碼中先使用該模塊。bash

from __future__ import division

該模塊支持的Python3的新特性以下的功能:機器學習

  • PEP 3105Make print a function
  • PEP 238Changing the Division Operator
  • PEP 3112Bytes literals in Python 3000 (unicode)
  • PEP 328Imports: Multi-Line and Absolute/Relative

print

print從2的statement變成了3的一個函數調用,在Python3調用print,必須使用函數的方式來調用,這個多是最廣爲人知的Python3的變化了。ide

# Python2 print is a statement
print 'Hello, World!'
print('Hello, World!')
print "text", ; print 'print more text on the same line'
Hello, World!
Hello, World!
text print more text on the same line
# Python3 print is a function
print('Hello, World!')
print("some text,", end="")
print(' print more text on the same line')
Hello, World!
some text, print more text on the same line

除法運算函數

Python3除法運算的改動比較危險,由於改動的是計算的行爲,語法上是徹底同樣的,也就是說,一樣的代碼在2和3的環境下可能會返回不一樣的結果。工具

#python2 Division
print '3 / 2 =', 3 / 2
print '3 // 2 =', 3 // 2
print '3 / 2.0 =', 3 / 2.0
print '3 // 2.0 =', 3 // 2.0
3 / 2 = 1
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.0
# Python3 division
print('3 / 2 =', 3 / 2)
print('3 // 2 =', 3 // 2)
print('3 / 2.0 =', 3 / 2.0)
print('3 // 2.0 =', 3 // 2.0)
3 / 2 = 1.5
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.0

unicode

Python2的unicode,str,bytearray是三個不一樣的類型,而在3中,bytes和bytesarray都成爲了類。Python3提供了對unicode的直接支持。oop

# Python2 unicode/str/bytearray are 3 types
print type(unicode('this is like a python3 str type'))
print type(b'byte type does not exist')
print 'they are really' + b' the same'
print type(bytearray(b'bytearray oddly does exist though'))
<type 'unicode'>
<type 'str'>
they are really the same
<type 'bytearray'>
# Python3 bytes and bytearray are two classed
print(type(b' bytes for storing data'))
print(type(bytearray(b'bytearrays')))
print('strings are now utf-8 \u4F60\u597D\u4E16\u754C!')
<class 'bytes'>
<class 'bytearray'>
strings are now utf-8 你好世界!

import

Python2和Python3對於import的主要區別在於:

  • Python2默認相對路徑import,Python3默認絕對路徑import
  • Python2須要在文件夾下建立 __init__.py文件才能把這個文件目錄做爲包來導入。在Python3.3之後,全部的目錄都被看做是包,而無需__init__.py文件。
  • Python 2, 支持在函數哪調用 from <module> import * . Python 3, 像 from <module> import * 這樣的語法只能在模塊級別調用,不能在函數內調用

range and xrange

Python2 range返回一個list,而Python3 range返回一個range類的對象。

# Python2 range
print range(0,10,1)
print type(range(0,10,1))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
<type 'list'>
# Python3 range return a object
print(range(0,10,1))
print(type(range(0,10,1)))
print(list(range(0,10,1)))
range(0, 10)
<class 'range'>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

xrange在Python2中常常被使用,咱們知道xrange是一個生成器。由於在3中range的行爲和xrange同樣,因此xrange在Python3中被delete了。

迭代器的next()方法

在Python2中,能夠調用next函數或者迭代器對象的.next()方法,在Python3中,.next()方法被刪除了。

# Python2 next
my_generator = (letter for letter in 'abcdefg')
print(next(my_generator))
print my_generator.next()
a
b
# Python3 next
my_generator = (letter for letter in 'abcdefg')
print(next(my_generator))
a

For-loop variables

看栗子

# Python2 Loop 
i = 1
print 'before: i =', i
print 'comprehension: ', [i for i in range(5)]
print 'after: i =', i
before: i = 1
comprehension:  [0, 1, 2, 3, 4]
after: i = 4

在Python2中,列推導表達式和它以外的代碼擁有相同的命名空間,也就是說,for loop中的變量i和以前的全局變量i實際上是一個。這個多是一個危險的行爲。

# Python3 loop 
i = 1
print('before: i =', i)
print('comprehension:', [i for i in range(5)])
print('after: i =', i)
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 1

Python3的列推導表達式擁有獨立的命名空間,不會污染到全局變量。

比較不可比較的類型

Python2,你能夠對任何類型進行比較

# Python2 unordered type
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] > 'foo' =  False
(1, 2) > 'foo' =  True
[1, 2] > (1, 2) =  False

鬼才知道爲何由1/2組成的列表比‘foo’要大,而一樣的集合就小。Python3會返回Type Error

TypeError: unorderable types: list() > str()

 

四捨五入

Python2 採用的是四捨五入

# Python2 rounding
print round(15.5)
print round(16.5)
16.0
17.0

Python3採用國際最新的「銀行家規則」,該規則並非簡單「四捨六入五取偶」,而是隻有在精確的 0.5 的狀況下才會取偶,不然仍是要四捨五入的。

# Python3 banker's rounding
print(round(15.5))
print(round(16.5))
16
16

Classes

IPython 2 支持兩種類型的類 「old-style」 和 「new-style」或者「classic-style」. 而Python3只支持「new-style」 

Type Annotation

類型標註

Python2的類型標註是利用註釋來實現的

# Python2 Type Hint
def embezzle(self, account, funds=1000000, *fake_receipts):
    # type: (str, int, *str) -> None
    """Embezzle funds from account using fake receipts."""
    <code goes here>

Python3.5開始支持原生的typing

# Python3 Typing
def embezzle(self, account: str, funds :int =1000000, *fake_receipts : *str): -> None
    """Embezzle funds from account using fake receipts."""
    <code goes here>

以上是一些主要和常見的差別,更多的細節你們能夠在後面的參考中去找。

遷移指南

當你決定要遷移到Python3,那麼你要作的是:

  1. 肯定你的全部的依賴支持Python3
  2. 運行測試,確保你的全部的代碼都能經過測試
  3. 進行代碼遷移,這裏你可能會用到一些工具
    1. six Python2 和 3 兼容庫
    2. 利用 futurize 或者 modernize 
      Futurize就是在Python2中使用將來的Python3的功能,而Modernize正相反,使用Python2/3的兼容子集,利用six來提供兼容性。你能夠選擇任何一種方式。
    3. 使用pylint 來分析代碼中和Python3不兼容的地方。
  4. 當你組件遷移到Python3,你可能會使用tox來保證兼容2,tox支持建立不一樣的python環境來進行測試。
  5. 開始使用類型檢查

咱們組的小夥伴已經興高采烈,火燒眉毛的把代碼都趕到Python3的一邊了,你有沒有計劃呢?但願這篇文章可以幫助你下個決定吧!

參考

相關文章
相關標籤/搜索