Python2.x将很快失去官方支持,但尽管如此,从Python2迁移到Python3并不像您想象的那么困难。上周我花了一个晚上将3D渲染器的前端代码及其对应的PySide迁移到Python3,现在回想起来,尽管一路上不可避免地出现了一些小问题,但与痛苦的重构相比,整个过程出奇的简单。大家都迫于各种原因不得不迁移:可能是感觉拖得太久了,可能是依赖了某个模块,Python2下不再维护了。但是如果你只是想为开源贡献一份力量通过做某事获取源代码,然后将Python2应用程序迁移到Python3是一种简单而有意义的方法。无论出于何种原因从Python2迁移到Python3,这都是一项重要任务。遵循这三个步骤将使您能够更清楚地完成任务。1.使用2to3从几年前开始,Python就在你不知不觉中附带了一个名为2to3的脚本,它可以帮助你自动将大部分代码从Python2转换为Python3。下面是一段用Python2.6编写的代码:#!/usr/bin/envpython#-*-coding:utf-8-*-mystring=u'abcdé'printord(mystring[-1])执行2to3脚本它:$2to3example.pyRefactoringTool:Refactoredexample.py---example.py(原始)+++example.py(重构)@@-1,5+1,5@@#!/usr/bin/envpython#-*-编码:utf-8-*--mystring=u'abcdé'-printord(mystring[-1])+mystring='abcdé'+print(ord(mystring[-1]))重构工具:需要修改的文件:重构工具:例子。py默认情况下,2to3只会标记迁移到Python3时必须修改的代码。输出中显示的Python3代码可以直接使用,但您可以在2to3参数中添加-w或--write,这样就可以根据给定的方案直接修改您的Python2代码文件。$2to3-wexample.py[...]RefactoringTool:Filesthatweremodified:RefactoringTool:example.py2to3脚本不仅对单个文件有效,你也可以对一个目录下的所有Python文件使用,它还会递归所有Python子目录中的文件生效。2.使用Pylint或者Pyflakes,有一些不好的代码在Python2下运行无一例外,但是在Python3下运行时,或多或少会报错。这种情况并不少见。由于这些错误代码无法通过语法转换来修复,因此2to3对它们没有影响,但是一旦使用Python3运行它就会产生错误。要发现这类问题,需要使用Pylint、Pyflakes(或flake8wrapper)等工具。其中,我更喜欢Pyflakes,它忽略了代码风格的差异,在这一点上与Pylint不同。虽然代码美观是Python的一大特色,但在代码迁移层面,“保持代码功能一致”无疑比“让代码风格一致”重要得多。这是Pyflakes的示例输出:$pyflakesexample/mathsexample/maths/enum.py:19:undefinedname'cmp'example/maths/enum.py:105:localvariable'e'isassignedtobutneverusedexample/maths/enum.py:109:undefinedname'basestring'example/maths/enum.py:208:undefinedname'EnumValueCompareError'example/maths/enum.py:208:localvariable'e'isassignedtobutneverused以上Pyflakes输出的内容很清楚的说明了代码中需要修改的问题.相比之下,Pylint输出多达143行,而且大部分都是代码缩进之类的琐碎事情。值得注意的是第19行的误导性错误。从输出中,您可能会认为cmp在使用之前是未定义的变量。cmp其实是Python2的内置函数,在Python3中被去掉了。而且这段代码是放在一个try语句块中的,除非仔细检查这段代码的输出值,否则很容易出现这个问题被忽视了。try:result=cmp(self.index,other.index)except:result=42returnresult在代码迁移过程中,你会发现很多原本在Python2中正常运行的函数都变了,甚至直接在Python3中被去掉了。比如PySide的bindings变了,importlib换成了imp等等。这种问题只能一一解决,需要权衡涉及到的功能是需要重构还是直接放弃。但就目前而言,大多数问题都是已知的并且有据可查。所以难的不是解决问题,而是发现问题。从这个角度来说,使用Pyflake是很有必要的。3.修复损坏的Python2代码虽然2to3脚本可以帮助您修改代码以兼容Python3,但对于完整的代码库来说有点力不从心,因为一些旧代码在Python3中可能需要不同的结构来表示.在这种情况下,只能手动修改。例如下面的代码在Python2.6中可以正常运行:=CLOCK_SPEED.TICKS_PER_SECOND像2to3和Pyflakes这样的自动化工具无法检测到这个问题,但是如果上面的代码用Python3运行,解释器会认为CLOCK_SPEED.TICKS_PER_SECOND没有明确定义。因此,需要将代码改成面向对象的结构:classCLOCK_SPEED:defTICKS_PER_SECOND():TICKS_PER_SECOND=16TICK_RATES=[int(i*TICKS_PER_SECOND)foriin(0.5,1,2,3,4,6,8,11,20)]returnTICKS_PER_SECONDclassFPS:STATS_UPDATE_FREQUENCY=CLOCK_SPEED.TICKS_PER_SECOND()你可能会想如果把TICKS_PER_SECOND()改写成构造函数(使用__init__函数设置默认值),代码会看起来更简洁,但是你需要改变这个方法的调用形式,从CLOCK_SPEED.TICKS_PER_SECOND()改为CLOCK_SPEED(),这样的改变会对整个库产生一些未知的影响。如果你熟记整个代码库的结构,那么你确实可以随心所欲地进行这样的改动。但我通常认为,只要我进行更改,可能会影响其他代码中至少三个地方,所以我宁愿不更改代码的结构。信不信由你如果您正在尝试将一个大型项目从Python2迁移到Python3,您可能会觉得这是一个漫长的过程。你可能会尽力寻找有用的错误信息,在这种情况下,你甚至会有推倒重来的冲动。但从另一个角度来看,代码可以在Python2中运行,要让它继续在Python3中运行,只需要稍微转换一下就可以了。但是一旦完成迁移,您将获得此模块或整个应用程序的Python3版本,以及Python的官方长期支持。
