如何编写尽可能与Python 3.x兼容的Python 2.x?

在Python 2.x中包含Python 3.x特性的方法有很多,所以将来Python 2.x脚本的代码很容易转换成Python 3.x。 其中一个例子是用print()函数replaceprint语句:

 >>> from __future__ import print_function 

有什么清单或资源可以给出一些想法如何使Python 2.x代码尽可能接近Python 3.x?

你能举出一些其他有用的导入或定义的例子, 使得Python 2.x的外观和行为更像Python 3.x吗?

让我们假设我们有最新的Python 2.x(目前2.7.2,我相信)在我们的处置。

我正在对大约5000行进行最后的修改,删除在CPython 2上运行的备份程序( http://stromberg.dnsalias.org/~strombrg/backshift/)%5B567%5D,CPython 3。 (3.3仍然是alpha 0),Pypy 1.7和Jython主干。 我也试过IronPython,但是它是一个非常不同的东西 – 它没有标准的库,所以没有后移的爱。 哦,它可以使用Cython的最内层循环,或者psyco – 但是pypy比两者都快,特别是在32位系统上。

无论如何,我发现要编写在2.x和3.x上运行的代码,所有我需要做的是:

1)print(variables)在2.x和3.x上都是一样的。 打印(variables1,variables2)不。 对于2.x,print(variables)表示“评估这个括号expression式,并使用print语句打印单个结果”。 对于3.x,print(variable)表示“在这个单一的结果上调用print函数,所以print('abc%d%d'%(1,2))在两个函数中都能正常工作,因为它是一个单值结果,这两个grok%string格式的运算符。

2)避免八进制常量。 写(7 * 64 + 5 * 8 + 5),而不写0755。

3)要做二进制I / O,我用我的bufsock模块。 http://stromberg.dnsalias.org/~strombrg/bufsock.html我会os.open文件,并用bufsock包装(或在模块中使用rawio类)。; 在2.x上,这将返回一串字节编码为8位string。 在3.x中,这将返回一个字节对象,这个对象很像一个小整数列表。 然后,我只是绕过一个或另一个,根据需要testing“isinstance(foo,str)”来区分这两者。 我这样做,因为对于一个备份程序,字节是字节 – 我不想混乱编码保存数据可靠,并不是所有的编码往返旅行。

4)做例外时,避免使用“as”关键字。 相反,使用EG:

  try: self.update_timestamp() except (OSError, IOError): dummy, utime_extra, dummy = sys.exc_info() if utime_extra.errno == errno.ENOENT: 

5)在从2.x到3.x的转换中重新命名了一堆模块。 因此,请尝试将其中一个导入到其他空的模块中,例如:

 try: from anydbm import * except ImportError: from dbm import * 

…这将出现在一个模块本身,名称EG adbm.py。 然后,当我需要一个键值存储时,我会直接导入adbm,而不是直接使用2.x或3.x所需的两种不同的东西。 然后,我会把所有的东西都除了那个粗糙的模块,adbm.py – 以及像pylint不喜欢的东西。 这个想法是为了把所有可能的事情都解决了,除了每个模块都有一个例外情况,一个小模块中的“一切都得到了pylint”规则。

6)在2.x和3.x上运行自动unit testing和系统testing,然后在至less一个2.x解释器和至less一个3.x解释器上进行频繁testing。 我也经常对我的代码运行pylint,虽然只是检查2.5.x兼容性的pylint – 我在pylint获得3.x支持之前启动了项目。

7)我build立了一个小的“python2x3”模块,它有一些常量和可调用的元素,使生活更轻松: http ://stromberg.dnsalias.org/svn/python2x3/trunk/python2x3.py

8)b“文字在2.5中不起作用,尽pipe他们在2中工作。[67]。 我设置了一个constants_mod.py,它有很多通常在3.x中是文字的东西,并将它们从一个简单的string转换为“字节”types为2 .x或3.x. 所以它们在模块导入时被转换一次,而不是在运行时反复。 如果你的目标是2. [67] 可能还有更好的方法,但是当我开始Pypy项目时只能兼容2.5,而Jython依然如此。

9)在2.x中,长整数有一个L后缀。 在3.x中,所有整数都是很长的。 所以我只是尽量避免使用长整型常量。 2.x会根据需要提升一个整数,所以对于大多数情况来说,这似乎很好。

10)它可以帮助很多的python解释器来testing。 我build了2. [567] 和[3] 并将其藏在/ usr / local / cpython-xy /中以便于testing。 我还在/ usr / local中放了一些Pypy和Jython,以方便testing。 有一个脚本来自动化CPython构build是相当宝贵的。

我相信这些都是我在一个非常重要的项目中获得高度可移植的Python代码库所需的扭曲。 上面列出的列表中的一个大的遗漏是,我没有试图使用unicode对象 – 这是别人可能更有资格评论的东西。

HTH

你应该检查移植Python代码到3.0 。 虽然它旨在移植,但它回答了基本相同的问题。 你只是不会一路走来。

在“ 移植到Python 3 ”中有一整章的内容。 另外不要错过附录,列出语言差异与变通办法,以支持这两种语言。

你可能想要使用六个库 ,尽pipe没有它也可以。

将Python 2代码移植到Python 3是官方文档的一部分,仍然不能直接回答你的问题。

我有这个在我的Python 2.7脚本模板的顶部:

 from __future__ import division, print_function from future_builtins import ascii, filter, hex, map, oct, zip 

由于还没有提到:我发现这个备忘单对于这个确切的目的是非常有用的。