文檔翻譯 Python 2.7.x和Python 3.x之間的主要區別(包括示例)

許多Python初學者都想知道應該從哪一個版本的Python開始。我對這個問題的回答一般是「僅需使用您喜歡的教程所寫的版本,並在之後查看差別」。html

可是,若是您開始一個新項目並能夠選擇,該怎麼辦?我要說的是,只要Python 2.7.x和Python 3.x都支持您計劃使用的庫,那麼目前就沒有「對」或「錯」。可是,這兩個最受歡迎的Python版本之間的主要區別值得一看,以此避免在爲其中任何一個編寫代碼或計劃移植項目時碰見陷阱。python

 

__future__模塊

Python 3.x引入了一些Python 2不兼容的關鍵字和功能,能夠經過__future__Python 2 的內置模塊導入這些關鍵字和功能。__future__若是您打算爲代碼提供Python 3.x支持,建議使用import導入。例如,若是咱們想要Python 2中Python 3.x的整數除法行爲,則能夠經過如下方式將其導入git

from __future__ import division

__future__下表列出了能夠從模塊導入的更多功能:github

特徵 可選(版本) 強制(版本) 影響
nested_scopes 2.1.0b1 2.2 PEP 227靜態嵌套的合併範圍
generators 2.2.0a1 2.3 PEP 255簡單生成器
division 2.2.0a2 3.0 PEP 238更改除法運算符
absolute_import 2.5.0a1 3.0 PEP 328導入:多行和絕對/相對
with_statement 2.5.0a1 2.6 PEP 343「 with」聲明
print_function 2.6.0a2 3.0 PEP 3105使打印功能
unicode_literals 2.6.0a2 3.0 PEP 3112Python 3000中的字節字面量

(來源:[https://docs.python.org/2/library/__future__.html](https://docs.python.org/2/library/__future__.html#module-__future__))算法

from platform import python_version

打印功能

很是瑣碎,而且print語法中的更改多是最廣爲人知的更改,但仍然值得一提:Python 2的print語句已被該print()函數替換,這意味着咱們必須把要打印的對象包裝在括號中。app

若是咱們用Python 2的不帶括號的方式調用print功能, Python 2不會出現其餘額外問題,可是相反,Python 3會拋出一個SyntaxError函數

Python 2

print 'Python', python_version()
print 'Hello, World!'
print('Hello, World!')
print "text", ; print 'print more text on the same line'
Python 2.7.6
Hello, World!
Hello, World!
text print more text on the same line

Python 3

print('Python', python_version())
print('Hello, World!')

print("some text,", end="")
print(' print more text on the same line')
Python 3.4.1
Hello, World!
some text, print more text on the same line
print 'Hello, World!'
File "<ipython-input-3-139a7c5835bd>", line 1
  print 'Hello, World!'
                      ^
SyntaxError: invalid syntax

注意:oop

經過Python 2在上面打印「 Hello,World」看起來很「正常」。可是,若是在括號內有多個對象,則將建立一個元組,由於這個print在Python 2中是「語句」,而不是函數調用。ui

print 'Python', python_version()
print('a', 'b')
print 'a', 'b'
Python 2.7.7
('a', 'b')
a b

整數除法

若是您正在移植代碼,或者您正在Python 2中執行Python 3代碼,則此更改特別危險,由於整數除法行爲的更改一般不會引發注意(它不會引起SyntaxError)。 所以,我仍然傾向於在個人Python 3腳本中使用float(3)/23/2.0代替a 3/2,以避免給Python 2帶來麻煩(反之亦然,我建議在您的Python 2腳本中使用from __future__ import division )。this

Python 2

print 'Python', python_version()
print '3 / 2 =', 3 / 2
print '3 // 2 =', 3 // 2
print '3 / 2.0 =', 3 / 2.0
print '3 // 2.0 =', 3 // 2.0
Python 2.7.6
3 / 2 = 1
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.0

Python 3

print('Python', python_version())
print('3 / 2 =', 3 / 2)
print('3 // 2 =', 3 // 2)
print('3 / 2.0 =', 3 / 2.0)
print('3 // 2.0 =', 3 // 2.0)
Python 3.4.1
3 / 2 = 1.5
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.0

Unicode

Python 2具備ASCII str()類型,獨有類型unicode(),但沒有byte類型。

如今,在Python 3中,咱們終於有了Unicode(utf-8)strings和2個字節的類:bytebytearray

Python 2

print 'Python', python_version()
Python 2.7.6
print type(unicode('this is like a python3 str type'))
<type 'unicode'>
print type(b'byte type does not exist')
<type 'str'>
print 'they are really' + b' the same'
they are really the same
print type(bytearray(b'bytearray oddly does exist though'))
<type 'bytearray'>

Python 3

print('Python', python_version())
print('strings are now utf-8 \u03BCnico\u0394é!')
Python 3.4.1
strings are now utf-8 μnicoΔé!
print('Python', python_version(), end="")
print(' has', type(b' bytes for storing data'))
Python 3.4.1 has <class 'bytes'>
print('and Python', python_version(), end="")
print(' also has', type(bytearray(b'bytearrays')))
and Python 3.4.1 also has <class 'bytearray'>
'note that we cannot add a string' + b'bytes for data'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

<ipython-input-13-d3e8942ccf81> in <module>()
----> 1 'note that we cannot add a string' + b'bytes for data'


TypeError: Can't convert 'bytes' object to str implicitly

Xrange

在Python 2.x中,用xrange()在建立可迭代對象很是流行(例如在for循環或list / set-dictionary-comprehension 中)。 該行爲與生成器很是類似(即「惰性求值」),可是這裏的xrange-iterable不是窮舉的--這意味着,您能夠對其進行無限迭代。

因爲其「惰性求值」,range()的常規優點在於,若是您只須要對其進行一次迭代(例如,在for循環中),一般xrange()更快。可是,與一次迭代相反,這裏不建議重複屢次,由於每次生成都是從頭開始的!

在Python 3中,range()的實現相似於xrange()函數,所以xrange()再也不是專有函數(在Python 3中xrange()引起了NameError)。

import timeit

n = 10000
def test_range(n):
  return for i in range(n):
      pass

def test_xrange(n):
  for i in xrange(n):
      pass    

Python 2

print 'Python', python_version()

print '\ntiming range()'
%timeit test_range(n)

print '\n\ntiming xrange()'
%timeit test_xrange(n)
Python 2.7.6

timing range()
1000 loops, best of 3: 433 µs per loop


timing xrange()
1000 loops, best of 3: 350 µs per loop

Python 3

print('Python', python_version())

print('\ntiming range()')
%timeit test_range(n)
Python 3.4.1

timing range()
1000 loops, best of 3: 520 µs per loop
print(xrange(10))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)

<ipython-input-5-5d8f9b79ea70> in <module>()
----> 1 print(xrange(10))


NameError: name 'xrange' is not defined

 

Python 3中range對象的__contains__方法

值得一提的另外一件事是在Python 3.x 中range有了一個「新」 __contains__方法(感謝Yuchen Ying指出了這一點)。對於整數和布爾類型,該__contains__方法能夠大大加快Python 3.x中range的「查找」速度。

x = 10000000
def val_in_range(x, val):
  return val in range(x)
def val_in_xrange(x, val):
  return val in xrange(x)
print('Python', python_version())
assert(val_in_range(x, x/2) == True)
assert(val_in_range(x, x//2) == True)
%timeit val_in_range(x, x/2)
%timeit val_in_range(x, x//2)
Python 3.4.1
1 loops, best of 3: 742 ms per loop
1000000 loops, best of 3: 1.19 µs per loop

根據上面的timeit結果,您能夠看到當「查找」的執行對象是整數類型而不是浮點型時,執行速度提升了約60,000。可是,因爲Python 2.x rangexrange沒有__contains__方法,整數或浮點數的「查找速度」不會有太大不一樣:

print 'Python', python_version()
assert(val_in_xrange(x, x/2.0) == True)
assert(val_in_xrange(x, x/2) == True)
assert(val_in_range(x, x/2) == True)
assert(val_in_range(x, x//2) == True)
%timeit val_in_xrange(x, x/2.0)
%timeit val_in_xrange(x, x/2)
%timeit val_in_range(x, x/2.0)
%timeit val_in_range(x, x/2)
Python 2.7.7
1 loops, best of 3: 285 ms per loop
1 loops, best of 3: 179 ms per loop
1 loops, best of 3: 658 ms per loop
1 loops, best of 3: 556 ms per loop

在該__contain__方法還沒有添加到Python 2.x 的「proofs」之下:

print('Python', python_version())
range.__contains__
Python 3.4.1





<slot wrapper '__contains__' of 'range' objects>
print 'Python', python_version()
range.__contains__
Python 2.7.7



---------------------------------------------------------------------------
AttributeError                           Traceback (most recent call last)

<ipython-input-7-05327350dafb> in <module>()
    1 print 'Python', python_version()
----> 2 range.__contains__


AttributeError: 'builtin_function_or_method' object has no attribute '__contains__'
print 'Python', python_version()
xrange.__contains__
Python 2.7.7



---------------------------------------------------------------------------
AttributeError                           Traceback (most recent call last)

<ipython-input-8-7d1a71bfee8e> in <module>()
    1 print 'Python', python_version()
----> 2 xrange.__contains__


AttributeError: type object 'xrange' has no attribute '__contains__'

注意Python 2和3中的速度差別

有人指出Python 3 range()和Python2 xrange()之間的速度差別。因爲它們以相同的方式實現,所以指望速度相同, 然而,確實存在的區別在於Python 3一般比Python 2的運行速度慢。

def test_while():
  i = 0
  while i < 20000:
      i += 1
  return
print('Python', python_version())
%timeit test_while()
Python 3.4.1
100 loops, best of 3: 2.68 ms per loop
print 'Python', python_version()
%timeit test_while()
Python 2.7.6
1000 loops, best of 3: 1.72 ms per loop

引起異常

在Python 2接受「舊」和「新」兩種表示法的狀況下,若是咱們不將異常參數括在括號中,則Python 3會阻塞(並引起一個SyntaxError的返回):

Python 2

print 'Python', python_version()
Python 2.7.6
raise IOError, "file error"
---------------------------------------------------------------------------
IOError                                   Traceback (most recent call last)

<ipython-input-8-25f049caebb0> in <module>()
----> 1 raise IOError, "file error"


IOError: file error
raise IOError("file error")
---------------------------------------------------------------------------
IOError                                   Traceback (most recent call last)

<ipython-input-9-6f1c43f525b2> in <module>()
----> 1 raise IOError("file error")


IOError: file error

Python 3

print('Python', python_version())
Python 3.4.1
raise IOError, "file error"
File "<ipython-input-10-25f049caebb0>", line 1
  raise IOError, "file error"
                ^
SyntaxError: invalid syntax

在Python 3中引起異常的正確方法:

print('Python', python_version())
raise IOError("file error")
Python 3.4.1



---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)

<ipython-input-11-c350544d15da> in <module>()
    1 print('Python', python_version())
----> 2 raise IOError("file error")


OSError: file error

處理異常

另外,在Python 3中對異常的處理也略有變化。在Python 3中,咱們如今必須使用「 as」關鍵字

Python 2

print 'Python', python_version()
try:
  let_us_cause_a_NameError
except NameError, err:
  print err, '--> our error message'
Python 2.7.6
name 'let_us_cause_a_NameError' is not defined --> our error message

Python 3

print('Python', python_version())
try:
  let_us_cause_a_NameError
except NameError as err:
  print(err, '--> our error message')
Python 3.4.1
name 'let_us_cause_a_NameError' is not defined --> our error message

 

next()函數和.next()方法

鑑於next().next())是一種如此經常使用的函數(方法),故值得一提的是另外一種語法更改(或更確切地說是實現上的更改):在Python 2.7.5中能夠同時使用函數和方法,該next()函數就是仍保留在Python 3中(調用.next()方法會引起AttributeError)。(本段待修正--譯者按)

Python 2

print 'Python', python_version()

my_generator = (letter for letter in 'abcdefg')

next(my_generator)
my_generator.next()
Python 2.7.6





'b'

Python 3

print('Python', python_version())

my_generator = (letter for letter in 'abcdefg')

next(my_generator)
Python 3.4.1





'a'
my_generator.next()
---------------------------------------------------------------------------
AttributeError                           Traceback (most recent call last)

<ipython-input-14-125f388bb61b> in <module>()
----> 1 my_generator.next()


AttributeError: 'generator' object has no attribute 'next'

For循環變量和全局名稱空間泄漏

好消息是:在Python 3.x中,for循環變量再也不泄漏到全局名稱空間中!

這能夠追溯到在Python 3.x中所作的更改,並在Python 3.0的新增功能中進行了以下描述:

 

"列表理解再也不支持語法形式[... for var in item1, item2, ...]。使用[... for var in (item1, item2, ...)]代替。還要注意,列表理解具備不一樣的語義:對於list()構造函數內部的生成器表達式,它們更接近語法糖,而且尤爲是循環控制變量再也不泄漏到周圍的範圍中。"

Python 2

print 'Python', python_version()

i = 1
print 'before: i =', i

print 'comprehension: ', [i for i in range(5)]

print 'after: i =', i
Python 2.7.6
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 4

Python 3

print('Python', python_version())

i = 1
print('before: i =', i)

print('comprehension:', [i for i in range(5)])

print('after: i =', i)
Python 3.4.1
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 1

比較無序類型

Python 3的另外一個不錯的變化是,若是咱們嘗試比較無序類型,則會引起TypeError警告。

Python 2

print 'Python', python_version()
print "[1, 2] > 'foo' = ", [1, 2] > 'foo'
print "(1, 2) > 'foo' = ", (1, 2) > 'foo'
print "[1, 2] > (1, 2) = ", [1, 2] > (1, 2)
Python 2.7.6
[1, 2] > 'foo' = False
(1, 2) > 'foo' = True
[1, 2] > (1, 2) = False

Python 3

print('Python', python_version())
print("[1, 2] > 'foo' = ", [1, 2] > 'foo')
print("(1, 2) > 'foo' = ", (1, 2) > 'foo')
print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))
Python 3.4.1



---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

<ipython-input-16-a9031729f4a0> in <module>()
    1 print('Python', python_version())
----> 2 print("[1, 2] > 'foo' = ", [1, 2] > 'foo')
    3 print("(1, 2) > 'foo' = ", (1, 2) > 'foo')
    4 print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))


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

 

經過input()解析用戶輸入

幸運的是,該input()函數已在Python 3中修復,所以它始終將用戶輸入存儲爲str對象。爲了不在Python 2中使用strings之外的其餘類型進行讀取的危險行爲,咱們必須改變raw_input()的使用。

Python 2

Python 2.7.6
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

>>> my_input = input('enter a number: ')

enter a number: 123

>>> type(my_input)
<type 'int'>

>>> my_input = raw_input('enter a number: ')

enter a number: 123

>>> type(my_input)
<type 'str'>

Python 3

Python 3.4.1
[GCC 4.2.1 (Apple Inc. build 5577)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

>>> my_input = input('enter a number: ')

enter a number: 123

>>> type(my_input)
<class 'str'>

返回可迭代對象而不是列表

如本xrange節所述,一些函數和方法如今在Python 3中返回可迭代對象-而不是Python 2中的列表。

因爲咱們一般只迭代一次,所以我認爲這種更改在節省內存方面頗有意義。可是,與生成器相比,若是須要的話,也有可能迭代屢次,至於此這並非那麼有效。

對於那些咱們確實須要list-objects的狀況,咱們能夠簡單的經過list()函數將可迭代對象轉換爲list

Python 2

print 'Python', python_version()

print range(3)
print type(range(3))
Python 2.7.6
[0, 1, 2]
<type 'list'>

Python 3

print('Python', python_version())

print(range(3))
print(type(range(3)))
print(list(range(3)))
Python 3.4.1
range(0, 3)
<class 'range'>
[0, 1, 2]

Python 3中一些再也不返回列表的更經常使用的函數和方法:

  • zip()

  • map()

  • filter()

  • 字典的.keys()方法

  • 字典的.values()方法

  • 字典的.items()方法

銀行家算法(四捨六入五成雙:譯者按)

當Python 3在最後一個有效數字處產生並列(.5)時,Python 3採用瞭如今的四捨五入方式。如今,在Python 3中,小數點將四捨五入爲最接近的偶數。儘管這對於代碼可移植性帶來了不便,可是與四捨五入相比,它被認爲是一種更好的舍入方式,由於它避免了偏向大數的狀況。有關更多信息,請參見優秀的的Wikipedia文章和段落:

Python 2

print 'Python', python_version()
Python 2.7.12
round(15.5)
16.0
round(16.5)
17.0

Python 3

print('Python', python_version())
Python 3.5.1
round(15.5)
16
round(16.5)
16

 

 

原文連接:  https://sebastianraschka.com/Articles/2014_python_2_3_key_diff.html#more-articles-about-python-2-and-python-3

做者:塞巴斯蒂安·拉施卡(Sebastian Raschka)

翻譯:  墨寒

相關文章
相關標籤/搜索