Supporting Python 3(支持python3)——語言區別和暫時解決方法

語言區別和暫時解決方法

這個附錄包含一個Python 2和Python 3的不一樣之處列表以及能不用2to3轉換同時在Python 2和Python 3下運行的示例代碼。html

這個列表是不完整的。在這裏列出的只有不包括bug修復的策劃變化,即便如此也可能有意外的遺漏。python

apply()

2to3 fixer ☑ six support ☐express

Python 2的內置apply()在Python 3已經被移除。它用於調用一個函數,但因爲你能夠直接調用函數它並無什麼用並從Python 2.3起被廢棄了。沒有替代方案。app

buffer()

2to3 fixer ☑ six support ☐編輯器

Python 2的buffer()內置函數被Python 3的類memoryview取代了。他們是不徹底兼容,因此2to3除非你顯示指定buffer固定器不然不會修改這個。函數

這個代碼能不用2to3轉換在Python 2和Python 3同時運行:測試

>>> import sys
>>> if sys.version_info > (3,):
...     buffer = memoryview
>>> b = buffer('yay!'.encode())
>>> len(b)
4

callable()

2to3 fixer ☑ six support ☑ui

Python 2的內置callable()在Python 3.0被移除,可是在Python 3.2從新引入。若是你須要支持Python 3.1你能夠用償試在try的監視下調用對象並在它不能調用時捕捉到一個TypeError。spa

若是你須要不用它來了解對象是否可調用,有幾種Python 3的解決方案:.net

>>> def afunction():
...     pass

>>> any("__call__" in klass.__dict__ for
...     klass in type(afunction).__mro__)
True

>>> import collections
>>> isinstance(afunction, collections.Callable)
True

若是你須要代碼能不用2to3轉換同時在Python 2和Python 3下運行,你能夠用這個:

>>> hasattr(bool, '__call__')
True

six模塊也定義了一個在Python 3下使用的callable函數。

Classes

2to3 fixer ☐ six support ☐

在Python 2有兩種類型的類,「舊式」和「新式」。「舊式」類已經在Python 3中被移除了。

另見使用新式的類

Comparisons

2to3 fixer ☐ six support ☐

Python 2內置cmp()已經在Python 3.0.1中被移除了,雖然它仍錯誤地留在了Python 3.0。它主要用於定義__cmp__比較方法或者做爲cmp的參數傳給.sort(),而且對它的支持也一樣在Python 3被移除了。

若是你須要cmp()你能夠像這樣定義它:

def cmp(a, b):
    return (a > b) - (a < b)

更多信息見Unorderable類型、__cmp__和cmp

coerce() and __coerce__

2to3 fixer ☐ six support ☐

coerce()內置函數和__coerce__方法在Python 3中已經被移除。coerce()將根據Python算術運行符的強制轉換規則轉換數字參數而且只在引入新數字類型的Python早期版本有用。沒有在Python 3中的替代方式;強制轉換應該被數字運行符方法代替來作。

字典方法

2to3 fixer ☑ six support ☐

在Python 2字典有用迭代器代替列表的iterkeys()、 itervalues() 和iteritems()方法。在Python 3標準的keys()、 values() 和items()返回字典視圖,字典視圖是一個迭代器,因此迭代器變種變得毫無心義並被移除了。

若是你須要不用2to3轉換同時支持Python 2和Python 3而且你必須使用迭代器方法,你能夠經過try/except來使用它:

>>> d = {'key1': 'value1',
...      'key2': 'value2',
...      'key3': 'value3',
... }

>>> try:
...     values = d.itervalues()
... except AttributeError:
...     values = d.values()
>>> isinstance(values, list)
False

>>> for value in values:
...     print(value)
value3
value2
value1

此外,字典的has_key()取消了。使用in操做符來代替。

另見確保你沒有用任何一個被移除的模塊

except

2to3 fixer ☑ six support ☐

在Python 2捕獲異常的語法已經人:

except (Exception1, Exception2), target:

改爲了明瞭的Python 3語法:

except (Exception1, Exception2) as target:

其餘不一樣是目標是能夠是元組的時間不長了而且字符串異常已經取消。2to3將會轉換除了字符串異常全部的這些。

兩種語法都能在Python 2.6和Python 2.7下工做,可是若是你須要不用2to3轉換在更早版本下執行,你能夠經過sys.exc_info()來獲取異常對象:

>>> import sys
>>> try:
...     raise Exception("Something happened")
... except Exception:
...     e = sys.exc_info()[1]
...     print(e.args[0])
Something happened

Exception對象

2to3 fixer ☑ six support ☐

在Python 2下異常對象是可能迭代和索引的:

>>> e = Exception('arg1', 'arg2')
>>> e[1]'
arg2'
>>> for a in e:
...   print a
...
arg1
arg2

在Python 3下你必需要用args屬性,這一樣能在Python 2下工做。

>>> e = Exception('arg1', 'arg2')
>>> e.args[1]
'arg2'
>>> for a in e.args:
...   print a
...
arg1
arg2

還有一個異常的message屬性在Python 2.5被引進,可是它在Python 2.6就已經被廢棄了,因此它不像是你會用的。

exec

2to3 fixer ☑ six support ☑

在Python 2下exec是這個語句:

>>> g_dict={}
>>> l_dict={}
>>> exec "v = 3" in g_dict, l_dict
>>> l_dict['v']
3

在Python 3下exec是一個函數:

>>> g_dict={}
>>> l_dict={}
>>> exec("v = 3", g_dict, l_dict)
>>> l_dict['v']
3

Python 3語法不用全局和局部字典的話也一樣能夠在Python 2下工做:

>>> exec("v = 3")
>>> v
3

若是你須要傳遞全局或者局部字典你須要定義一個帶有兩個實現的自定義函數,一個給Python 2,另外一個給Python 3。像往常同樣six包含一個這個的一個優秀實現叼着exec_()。

execfile

2to3 fixer ☑ six support ☐

Pyhton 2的execfile語句在Python 3已經取消了。做爲了一個替代,你能夠打開一個文件並讀取內容:

exec(open(thefile).read())

這個能夠在全部的Python版本工做。

file

2to3 fixer ☐ six support ☐

在Python 2有file內置類型。在Python 3這被多種文件類型取貨代了。大家常常看到Python 2使用file(pathname)的代碼在Python 3是失敗的。使用open(pathname)來替換這個用例。

若是你須要在Python 3下測試類型,能夠查檢io.IOBase來替代file。

filter()

2to3 fixer ☑ six support ☐

在Python 2下filter()返回一個列表,而在Python 3它返回一個迭代器。2to3在有些狀況下會用list()來包裹filter()的調用,以確保結果一直是一個列表。若是你須要不使用2to3轉換同時支持Python 2和Python 3而且須要要結果是一個列表,你能夠這樣作。

Imports

2to3 fixer ☑ six support ☐

在Python 2,若是你有一個叫着mypackage的包而且它包含一個叫着csv.py的模塊,它將會覆蓋標準庫的csv模塊。在mypackage裏的import csv代碼將會導入本地文件,從標準庫中導入將會變得棘手。

在Python 3,這已經改了,因此import csv會從標準庫導入,導入本地的csv.py文件你須要寫成from . import csv而且from csv import my_csv須要被改爲from .csv import my_csv。這些被叫着「相對導入」,而且也有一個語言來從上一級模塊導入:from .. import csv。

若是你不用2to3同時支持Python 2和Python 3,from .和 from ..語法和from __future__ import absolute_import語句起從Python 2.5就能夠用了,from __future__ import absolute_import語句能修改這個行爲成Python 3的行爲。

若是你須要支持Python 2.4或者更新的版本,你必需要講清楚整個包名,全部import csv變成from mypkg import csv而且from csv import my_csv變成from mypckg.csv import my_csv。爲了清晰和可讀性,我會盡量避免相對引用而且老是講清楚完整路徑。

2to3會檢查你的引用是否是本地的並修改他們。

縮進

2to3 fixer ☐ six support ☐

在Python 2做爲縮進一個tab等於八個空格,因此你能夠用tab來縮進行一行,並在下一行使用八個空格。若是你用的編輯器把tab擴展成非八空格的話,這將是混亂的。

在Python 3一個tab只等於另外一個tab。這意味着每個縮進等級必須是一致地使用tab或者空格。若是你有一個縮進塊有時使用tab有時候使用空的文件,你將得來到一個錯誤TabError: inconsistent use of tabs and spaces inindentation。

解決方法固然是去除不一致性。

input()和raw_input()

2to3 fixer ☑ six support ☐

在Python下有從stdin獲取字符串的raw_input()和從stdin獲取值並對其進行評估的input()。後一個函數由於不是頗有用,在Python 3中被移除了,而後raw_input()被重命名成input()。

>>> eval(input('Type in an expression: '))
'Type in an expression: ' 1+2
3

若是你的代碼須要不通過2to3轉換同時在Python 2和Python 3下執行,你能夠有條件地把input()設置成raw_input():

>>> try:
...     input = raw_input
... except NameError:
...     pass
>>> input('Type in a string: ')
Type in a string: It works!
'It works!'

整數相除

2to3 fixer ☐ six support ☐

在Python 2,兩個整數相除的結果是整數;換句話說3/2返回1。在Python 3整數相除老是返回一個浮點數。因此3/2會返回1.5,4/2會返回2.0。

若是你想舊的行爲你應該使用浮點除法運算符//來替代,這個從Python 2.2開始能夠用。若是你須要不用2to3轉換同時支持Python 2和Python 3,下面的__future__ import works從Python 2.2起可用,它可以容許新的行爲可用 :

>>> from __future__ import division
>>> 1/2
0.5

另見 當除以整數時用//代替/

long

2to3 fixer ☐ six support ☑ (partial)

Python 2有兩個整數類型int和long。這些在Python 3被統一了,因此如今只有一種類型,int。這意味着下面的代碼在Python 3會失敗:

>>> 1L
1L
>>> long(1)
1L

在Python 2至關常常地你須要聲明一個整數是long。若是你這麼作而且須要不經過2to3轉換代碼能同時在Python 2和Python 3下運行,下面的代碼能夠作到:

>>> import sys
>>> if sys.version_info > (3,):
...     long = int
>>> long(1)
1L

然而,表達一直都是不一樣的,因此文檔測試會失敗。

若是你須要檢查某物是否是一個數字,在Python 2下你須要分別檢查int和long,但在Python 3下只須要int。作這個的最好辦法下根據不一樣的Python版本設置一個integer_types元組並分別測試。six包含這個:

>>> import sys
>>> if sys.version_info < (3,):
...     integer_types = (int, long,)
... else:
...     integer_types = (int,)
>>> isinstance(1, integer_types)
True

map()

2to3 fixer ☐ six support ☐

在Python 2下map()返回一個列表,然而在Python 3它返回一個迭代器。2to3在一些狀況下會在map()調用的周圍調用list()以確保結果是一個列表。若是你須要代碼不經過2to3轉換能同時在Python 2和Python 3下運行而且你須要結果是一個列表,你也可能兩樣作這個。

在Python 2下map()會持續到最長的可迭代參數耗盡,另外一個參數會用None來擴展。

>>> def fun(a, b):
...    if b is not None:
...        return a - b
...    return -a
>>> map(fun, range(5), [3,2,1])
[-3, -1, 1, -3, -4]

在Python 3下map()取代的是在最短的參數那中止。若是你想要在Python 3中使用Python 2的行爲,你可使用starmap()和zip_longest()的組合。

>>> from itertools import starmap, zip_longest
>>> def fun(a, b):
...    if b is not None:
...        return a - b
...    return -a
>>> list(starmap(fun, zip_longest(range(5), [3,2,1])))
[-3, -1, 1, -3, -4]

Python 2的map()會接受None做爲它的函數參數,這裏它會僅僅返回傳入的對象。像這樣轉換map()成zip()不是特別有用,而且在Python 3這能工做的時間不長了。然而一些代碼是依賴這個行爲的,你可使用下面的函數來做爲Python 2的map替代者。

from itertools import starmap, zip_longest
def map(func, *iterables):
    zipped = zip_longest(*iterables)
    if func is None:
        # No need for a NOOP lambda here
        return zipped
    return starmap(func, zipped)

元類

2to3 fixer ☑ six support ☑

在Python 2使用__metaclass__來指定元類。在Python 3反而是在類定義傳入一個元類參數。不使用2to3轉換來在Python 2和Python 3中支持元類須要你匆匆忙忙建立一個類。若是你想作這個,我強烈建議使用six模塊,它有一個很是使人滿意的_metaclass()函數。

.next()

2to3 fixer ☑ six support ☑

在Python 2你能夠經過調用iterators.next()方法從迭代器獲取一下結果。在Python 3這被一個內置的next()取代。

若是你須要代碼不經過2to3轉換同時在Python 2和Python 3下運行,你能夠寫一函數在Python 2下調用iterator.next()在Python 3下調用next(iterator)。six模塊包含這種函數,叫着next(iterator)。

參數解包

2to3 fixer ☐ six support ☐

在Python 2你能夠作參數解包:

>>> def unpacks(a, (b, c)):
...     return a,b,c
>>> unpacks(1, (2,3))
(1, 2, 3)

Python 3不支持這個,因此你須要用你本身的解包來作:

>>> def unpacks(a, b):
...     return a,b[0],b[1]
>>> unpacks(1, (2,3))
(1, 2, 3)

print

2to3 fixer ☑ six support ☑

Python 2的print語句在Python 3是一個函數。若是你須要不使用2to3轉換在Python 2和Python 3下跑一樣的代碼,有多種技巧能夠作到這個。這個在支持print()函數裏討論。

raise

2to3 fixer ☑ six support ☑

在Python 2下raise語句的語法是:

raise E, V, T

這裏E是一個字符串、異常類或者一個異常實例,在E是一個類或者字符串的狀況下V是一個可選的異常值,T是一個你想到從不一樣於如今代碼的地方追蹤的追蹤對象。在Python 3這變成了:

raise E(V).with_traceback(T)

由於使用Python 2語法,值和追蹤是可選的。不帶追蹤變量的這個語法是:

raise E(V)

這能夠在全部的Python版本工做。很常常地你須要追蹤參數,可是若是你作了並須要寫出不用2to3能在Python 2和Python 3運行的代碼,你須要建立一個不一樣的帶有E、V和T參數的函數而且這個函數在Python 2和Python 3有不一樣的實現。six模塊對這個很好的實現,叫着reraise()。

range()和xrange()

2to3 fixer ☑ six support ☑

在Python 2下range()返回一個列表,xrange()只在須要時生成範圍內的項目以節省內存。

在Python 3,range()取消了,而且xrange()被重命名成range()。在Python 3.2及以後的版本增長了range()對象的切片支持。

2to3在一些狀況下會在調用range()的周圍放上一個list()調用,以確保結果是一個列表。若是你須要代碼不用2to3轉換在Python 2和Python2下能同時運行而且你須要結果是一個列表,你也能夠一樣這樣作。

你能夠從six模塊導入xrange()來確保你能同時在Python 2和Python 3下獲得這個迭代器變種。

repr()看成反撇號

2to3 fixer ☑ six support ☐

在Python 2你能夠經過反撇號包圍來生成一個表達式的字符串表示:

>>> `sorted`
'<built-in function sorted>'

>>> `2+3`
'5'

這個語法的惟一用途是讓新手困惑並混淆Python。它在Python 3已經被移除了,由於內置的repr()正好作了一樣的事。

>>> repr(sorted)'
<built-in function sorted>'

>>> repr(2+3)
'5'

湊整行爲

2to3 fixer ☐ six support ☐

在Python 3中round的行爲已經變了。在Python 2中途狀況的湊整老是遠離零,而且round()老是返回一個浮點數。

>>> round(1.5)
2.0
>>> round(2.5)
3.0
>>> round(10.0/3, 0)
3.0

在Python 3中途狀況的湊整如今老是朝向最接近的偶數。這是標準作法,由於它使得一個均勻分佈的集合湊整達到平均值。

第二個參數是限制小數的數量,當不用第二個參數調用時round()在Python 3中返回一個整數。若是你傳進一個參數來設置湊整的小數數量,返回值會變成和未湊整值相同的類型。即便你傳入的是一個零這也是正確的。

>>> round(1.5)
2
>>> round(2.5)
2
>>> round(10.0/3, 0)
3.0

若是你須要Python 2的行爲,你可使用下面的方法:

>>> import math
>>> def my_round(x, d=0):
...     p = 10 ** d
...     return float(math.floor((x * p) + math.copysign(0.5, x)))/p
>>> my_round(1.5)
2.0
>>> my_round(2.5)
3.0
>>> my_round(10.0/3, 0)
3.0

切片操做方法

2to3 fixer ☐ six support ☐

在Python 1你須要用__getslice__和__setslice__切片方法來讓你的對象支持像foo[3:7]這樣的切片操做。這些被廢棄了可是Python 2一直仍是支持。Python 3移除了切片方法的支持,因此你須要擴展__getitem__、__setitem__ 和__delitem__而不是切片對象支持。

>>> class StrawberryTart(object):
...
...    def __getitem__(self, n):
...        """An example of how to use slice objects"""
...        if isinstance(n, slice):
...            # Expand the slice object using range()
...            # to a maximum of eight items
....            return [self[x] for x in
...                    range(*n.indices(8))]
...
...        # Return one item of the tart
...        return 'A slice of StrawberryTart with ' \
...               'not so much rat in it.'
...
>>> tart = StrawberryTart()
>>> tart[5:6]
['A slice of StrawberryTart with not so much rat in it.']

排序

2to3 fixer ☐ six support ☐

在Python 2列表的.sort()方法和內置的sorted()都帶cmp和key這兩個參數。在Python 3只支持key參數。沒有固定器來作這個,因此你須要在Python 2代碼中修改。

更多信息見當排序時,使用key來代替cmp

StandardError

2to3 fixer ☑ six support ☐

Python 2有一個在Python 3已經被移除的叫做StandardError的異常類。使用Exception來替代它。

字符串類型

2to3 fixer ☑ six support ☑

Python 2有兩種字符串類型;str和unicode。Python 3只有一個;str,可是此外它還有一個bytes類型來處理二進制數據。更的信息見單獨的二進制數據和字符串更多的字節、字符串和Unicode

附註:

[1] http://pypi.python.org/pypi/six


本文地址:http://my.oschina.net/soarwilldo/blog/533438

在湖聞樟注:

原文http://python3porting.com/differences.html

引導頁Supporting Python 3:(支持Python3):深刻指南

目錄Supporting Python 3(支持Python 3)——目錄

相關文章
相關標籤/搜索