Supporting Python 3(支持python3)——语言区别和暂时解决方法

我是研究僧i 提交于 2019-12-06 05:45:32

语言区别和暂时解决方法

这个附录包含一个Python 2和Python 3的不同之处列表以及能不用2to3转换同时在Python 2和Python 3下运行的示例代码。

这个列表是不完整的。在这里列出的只有不包括bug修复的策划变化,即使如此也可能有意外的遗漏。

apply()

2to3 fixer ☑ six support ☐

Python 2的内置apply()在Python 3已经被移除。它用于调用一个函数,但由于你可以直接调用函数它并没有什么用并从Python 2.3起被废弃了。没有替代方案。

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 ☑

Python 2的内置callable()在Python 3.0被移除,但是在Python 3.2重新引入。如果你需要支持Python 3.1你可以用偿试在try的监视下调用对象并在它不能调用时捕捉到一个TypeError。

如果你需要不用它来了解对象是否可调用,有几种Python 3的解决方案:

>>> 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)——目录


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!