Python3支持策略

Python3支持策略

关于迁移

关于移植应用的官方文档(http://zeromq.org/)是有的,但不建议不折不扣地参考它。

最好还是兼容py2和py3,然后有够用的单元测试。
通过tox,来测试两个版本。
tox -e py27, py35
根据提示的错误进行修改,重新运行tox,直到所有测试都通过为止。

语言和标准库

Porting to Python3这本书给出了要支持Python3所需做修改的良好概述。

支持Python的多版本时,应该尽量避免同时支持Python3.3和早于Python2.6的版本。Python2.6是第一个为向Python3移植提供足够兼容性的版本。

影响你最多的可能是字符串处理方面。在Python3中过去称为unicode,现在叫做str。这意味着任何字符串都是Unicode的。也就是说u’foobar’和’foobar’是同一样东西。

实现unicode方法的类应该将其重命名为str,因为unicode方法将不再使用。可以通过一个类装饰器自动完成这个过程。

# -*- encoding: utf-8 -*-
import six


def unicode_compat(klass):
    if not six.PY3:
        klass.__unicode__ = klass.__str__
        klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
    return klass


class Square(object):
    def __str__(self):
        return u"" + str(id(self))

这种方式可以针对所有返回Unicode的Python版本实现一个方法,装饰器会处理兼容性问题。

另一个处理Python和Unicode的技巧是使用unicode_literals,它从Python2.6开始提供。

>>> 'foobar'
'foobar'
>>> from __future__ import unicode_literals
>>> 'foobar'
u'foobar'
>>>

许多函数不再返回列表而是返回可迭代对象(如range)。此外,字典方法(如keys或者iterms)现在也返回可迭代对象,而函数iterkeys和iteritems则已经被删除。 这是一个巨大的变化,但six将帮你处理这个问题。

显然,标准库也经历了从Python2到Python3的演化,但无需过分担心。一些模块已经被重命名或者删除,但最终呈现的是更为清晰的布局。我不知道是否有官方的清单,但是http://docs.pythonsprints.com/python3_porting/py-porting.html就有一份很好的清单,或者也可以用搜索引擎找到。

外部库

选择外部库时,最好一开始就兼容py3。如果已有库还不支持py3,没啥好办法。
另外用外部库时,最好自己有个中间层,这样将来换的时候也比较方便。

使用six

Python3破坏了与早期版本间的兼容性并且周边很多东西发生了变化。但是,这门语言的基础并没有发生变化,所以是可以实现一种转换层的,也就是一个能实现向前和向后兼容的模块–Python2和Python3之间的桥梁。

这样的模块是有的,名字就叫做six,因为2×3=6.
six首先要做的就是提供一个名为six.PY3的变量。它是一个布尔值,用来表明是否正在运行Python3。对于任何有两个版本(Python2和Python3)的代码库而言这都是一个关键变量。不过在用的时候要谨慎,如果代码中到处都是if six.PY3,那么后续会很难维护。

python3中,去掉了dict.iteritems,同时dict.items将返回一个迭代器而不是列表。显然,这会破坏你的代码。six对此提供了six.iteritems,使得所有要做的只是将

for k, v in mydict.iteritems():
    print(k, v)

替换为

import six

for k, v in six.iteritems(mydict):
    print(k, v)

看,Python3的兼容性立刻就解决了!six提供了大量类似的辅助函数以提升不同版本间的兼容性。

raise 在six中可以用 six.reraise。
如果正在使用abc抽象基类元类,则可以像下面这样使用six:

import abc
from six import with_metaclass

class MyClass(with_metaclass(abc.ABCMeta, object)):
    pass

six还有好多类似这样的模块,它是开源的,你也可以参与维护。

最后需要提及的是modernize模块。它是在2to3之上的一层很薄的包装器,用来通过迁移代码到Python3使其’现代化’。但是不同于单纯转化语法为Python3代码,它使用six模块。如要迁移,建议用用。

Tags:
15 Comments