我正在完成一个大约5000行的去重备份程序(http://stromberg.dnsalias.org/~strombrg/backshift/),可以运行在CPython 2.[567]、CPython 3.[0123](3.3仍处于alpha 0阶段)、Pypy 1.7和Jython trunk上。我也尝试了IronPython,但它是一种非常不同的东西——它没有标准库,因此没有backshift支持。哦,它可以使用Cython作为其最内层循环或者psyco - 但是pypy比这两个都快,特别是在32位系统上。
总之,我发现要编写能够在2.x和3.x上运行得同样良好的代码,我只需要做到以下几点:
1)print(variable)在2.x和3.x上的表现相同。而print(variable1, variable2)则不同。对于2.x,print(variable)表示“评估这个带括号的表达式,并使用print语句打印单个结果”。而对于3.x,print(variable)表示“对这个单个结果调用print函数”。因此,print('abc %d %d' % (1, 2))在这两个版本中都能正常工作,因为它是一个单值结果,并且两者都理解%操作符用于字符串格式化。
2)避免使用八进制常量。不要写0755,而是写(7*64 + 5*8 + 5)。
3)在任一版本中进行二进制I/O,我都使用了我的bufsock模块。http://stromberg.dnsalias.org/~strombrg/bufsock.html 我会os.open一个文件,并用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:
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不喜欢的东西。 这个想法是尽可能对所有内容进行pylint检查,在一个小模块中例外处理“一切都必须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的b''文字,并将它们从简单字符串转换为2.x或3.x的“bytes”类型。 因此,它们在模块导入时仅转换一次,而不是在运行时反复转换。 如果您的目标是2.[67]及以上版本,则可能有更好的方法,但是当我开始Pypy项目时,它只与2.5兼容,而Jython仍然是。
9)在2.x中,长整数具有L后缀。 在3.x中,所有整数都是long类型。 所以我尽量避免使用长整型常量; 2.x会根据需要将整数提升为长整型,因此这对于大多数东西似乎很好。
10) 拥有一堆Python解释器非常有帮助。 我构建了2.[567]和3.[0123]并将它们存储在/usr/local/cpython-x.y/中以进行方便测试。 我还将一些Pypy和Jython放在/usr/local中,以方便测试。 编写自动化CPython构建脚本非常有价值。
我相信这些都是我在一个非常复杂的项目中需要采取的所有姿势。 上面提到的一个重要的遗漏是,我没有尝试使用Unicode对象-这是其他人可能更有资格发表评论的事情。
希望对您有所帮助
u''
语法! - Robert Siemer