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

Tad*_*eck 35 python compatibility python-2.x python-3.x

有许多方法可以在Python 2.x中包含Python 3.x功能,因此Python 2.x脚本的代码将来可以很容易地转换为Python 3.x. 其中一个例子是用函数替换print语句print():

>>> from __future__ import print_function
Run Code Online (Sandbox Code Playgroud)

是否有任何列表或资源可以提供一些想法如何使Python 2.x代码尽可能接近Python 3.x?

您能举例说明其他有用的导入或定义可以使Python 2.x的外观和行为更像Python 3.x吗?

让我们假设我们拥有最新的Python 2.x(目前为2.7.2,我相信).

dst*_*erg 22

我正在对大约5000行进行最后润色,重复删除在CPython 2上运行的备份程序(http://stromberg.dnsalias.org/~strombrg/backshift/).[567],CPython 3.[0123] (3.3仍然是alpha 0),Pypy 1.7和Jython trunk.我也试过IronPython,但这是一个非常不同的东西 - 它没有标准的库,所以没有回溯的爱.哦,它可以使用Cython作为其最内层的循环,或psyco - 但pypy比任何一个都快,特别是在32位系统上.

无论如何,我发现编写在2.x和3.x上同样运行良好的代码我需要做的就是:

1)print(变量)在2.x和3.x上的工作方式相同.print(variable1,variable2)没有.对于2.x,print(变量)表示"评估此括号表达式,并使用print语句打印单个结果".至3.x,print(变量)表示"在此单个结果上调用打印函数.因此print('abc%d%d'%(1,2))在两者中都能正常工作,因为它是单值结果,并且两者都使用%运算符进行字符串格式化.

2)避免八进制常数.写入(7*64 + 5*8 + 5)而不是写0755.

3)要在二者中进行二进制I/O,我使用了我的bufsock模块. http://stromberg.dnsalias.org/~strombrg/bufsock.html 我打开一个文件,用bufsock包装它(或者使用模块中的rawio类).在2.x上,这将返回一个编码为8位字符串的字节串.在3.x上,这将返回一个bytes对象,其行为很像一个小整数列表.然后我只是绕过一个或另一个,根据需要用"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:
Run Code Online (Sandbox Code Playgroud)

5)在从2.x到3.x的过渡中重命名了一堆模块.因此,尝试将其中任何一个导入到其他空模块中,例如:

try:
   from anydbm import *
except ImportError:
   from dbm import *
Run Code Online (Sandbox Code Playgroud)

...这将出现在模块中,名称为EG adbm.py. 然后,只要我需要一个键值存储,我就会直接导入adbm而不是2.x或3.x所需的两个不同的东西.然后我会把除了那个粗短模块,adbm.py之外的所有东西都拼写出来 - 以及像pylint不喜欢的东西.我们的想法是尽可能地将所有可能的东西都列入一个小模块中的"一切都要有重要性"规则的例外,每个模块都有一个例外.

6)设置在2.x和3.x上运行的自动单元测试和系统测试很有帮助,然后经常在至少一个2.x解释器以及至少一个3.x解释器上进行测试.我经常对我的代码运行pylint,虽然只是检查2.5.x兼容性的一个pylint - 我在pylint获得3.x支持之前启动了项目.

7)我设置了一个小的"python2x3"模块,它有一些常量和可调用的东西,可以让生活更轻松:http://stromberg.dnsalias.org/svn/python2x3/trunk/python2x3.py

8)b''文字在2.5中不起作用,尽管它们在2中有效.[67].我没有尝试预处理或者某些东西,而是设置了一个constants_mod.py,其中包含许多通常是3.x中的文字的东西,并将它们从简单的字符串转换为2的"字节"类型. .x或3.x. 所以它们在模块导入时被转换一次,而不是在运行时反复转换.如果你的目标是2. [67] 而且,也许有更好的方法,但是当我开始时,Pypy项目只与2.5兼容,而Jython仍然是.

9)在2.x中,长整数具有L后缀.在3.x中,所有整数都很长.所以我尽量避免使用长整数常量; 2.x会根据需要将整数提升为long,因此对于大多数事情来说这似乎都很好.

10)有很多python解释器可供测试.我建造了2. [567] 和[0123] 并将它们存储在/ usr/local/cpython-xy /中以便于测试.我还在/ usr/local中添加了一些Pypy和Jython,以便于测试.拥有一个自动化CPython构建的脚本是非常有价值的.

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

HTH


DNS*_*DNS 7

您应该查看将Python代码移植到3.0.虽然它的目的是移植,但它基本上回答了同样的问题; 你不会一直走的.


Len*_*bro 7

在" 移植到Python 3 "中有一整章.另外,请不要错过附录,列出语言差异以及支持两种语言的变通方法.

你可能想要使用六个库,虽然没有它可以做到这一点.


Pao*_*olo 5

将 Python 2 代码移植到 Python 3是官方文档的一部分,但仍然没有直接回答您的问题,可能会有所帮助。