python 应用程序
Python 2.x系列正式于2020年1月结束 ,并且在2020年4月之后不再受支持 ,但是将代码转换为Python 3比您想象的要容易。 整个周末,我花了一个晚上将3D渲染器(及其对应的Qt / PySide版本的Python)的前端代码转换为Python 3,回想起来很简单,尽管在重构过程中看起来似乎毫无希望。 转换过程似乎有点迷宫,您所做的每一项更改都会揭示您需要进行的十几项更改。
您可能想要或可能不想进行转换,但是-是因为拖延太久还是依赖于除非进行转换就无法维护的模块-有时您别无选择。 而且,如果您正在寻找一项轻松的任务来开始为开源做贡献,那么将Python 2应用程序转换为Python 3是一种轻松而有意义的印象的好方法。
无论您出于什么原因将Python 2代码重构为Python 3,这都是一项重要的工作。 这是三个清晰地完成任务的步骤。
1.运行2至3
在过去的几年中,Python附带了一个名为2to3的脚本,该脚本为您完成了从Python 2到Python 3的大部分转换。 自动。 并且您已经安装了它(无论您是否意识到)。
这是用Python 2.6编写的一小段代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
mystring
= u
'abcdé'
print
ord
( mystring
[ -
1
]
)
运行2to3脚本:
$ 2to3 example.
py
RefactoringTool: Refactored example.
py
--- example.
py
( original
)
+++ example.
py
( refactored
)
@@ -
1
,
5 +
1
,
5
@@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-mystring
= u
'abcdé'
-
print
ord
( mystring
[ -
1
]
)
+mystring
=
'abcdé'
+
print
(
ord
( mystring
[ -
1
]
)
)
RefactoringTool: Files that need to be modified:
RefactoringTool: example.
py
默认情况下, 2to3仅打印使旧的Python代码达到Python 3标准所需的更改。 输出是一个可用的补丁,您可以使用它来更改文件,但是使用--write (或-w )选项,让Python为您轻松完成此操作更容易:
$ 2to3 -w example.
py
[ ...
]
RefactoringTool: Files that were modified:
RefactoringTool: example.
py
2to3脚本不能仅在单个文件上运行。 无论是否带有--write选项,您都可以在Python文件的整个目录上运行它,以处理该目录及其子目录中的所有* .py文件。
2.使用Pylint或Pyflakes
发现在Python 2中没有问题但在Python 3中无法正常运行的代码怪异现象并不少见,因为无法通过转换语法来修复这些怪异现象,因此它们在2to3不变的情况下会保持不变,但是一旦您尝试执行,它们就会失败。运行代码。
为了检测这样的问题,你可以像使用应用pylint的或类似的工具Pyflakes (或flake8包装)。 我更喜欢Pyflakes,因为与Pylint不同,它忽略了代码风格的偏差。 尽管通常将Python的“精美性”作为其优点之一,但将其他人的代码从2移植到3时,将样式和功能作为两个独立的bug进行处理是一个优先事项。
这是Pyflakes的示例输出:
$ pyflakes example/maths
example/maths/enum.
py :
19 : undefined name
'cmp'
example/maths/enum.
py :
105 : local variable
'e'
is assigned to but never used
example/maths/enum.
py :
109 : undefined name
'basestring'
example/maths/enum.
py :
208 : undefined name
'EnumValueCompareError'
example/maths/enum.
py :
208 : local variable
'e'
is assigned to but never used
此输出(与Pylint的143行比较,其中大多数是关于缩进的投诉)清楚地显示了您应修复的代码中的问题。
这里最有趣的错误是第19行的第一个错误。这有点误导,因为您可能会认为cmp是从未定义的变量,但是cmp实际上是Python 2中的一个函数,在Python 3中不存在。它包装在try语句中,因此在很明显没有产生try结果之前,很容易忽略该问题。
try :
result
=
cmp
(
self .
index
, other.
index
)
except :
result
=
42
return result
在将应用程序维护为Python 2代码库与决定移植该应用程序之间,存在无数个不再存在或已更改的函数示例。 PySide(2)绑定已更改,Python函数已消失或已转换(例如imp到importlib ),等等。 遇到它们时,一一修复。 即使由您决定重新实现或替换那些缺少的功能,到目前为止,大多数这些问题是已知的并有据可查 。 真正的挑战更多是要抓住错误,而不是要纠正它们,因此请使用Pyflakes或类似的工具。
3.修复损坏的Python 2代码
2to3脚本使您的代码与Python 3兼容,但只知道Python 2和3之间的差异。它通常无法进行调整以说明库中自2010年以来一直起作用但自那时以来进行了重大修订的更改。 您必须手动更新该代码。
例如,这段代码显然可以追溯到Python 2.6的时代:
class CLOCK_SPEED:
TICKS_PER_SECOND
=
16
TICK_RATES
=
[
int
( i * TICKS_PER_SECOND
)
for i
in
(
0.5
,
1
,
2
,
3
,
4
,
6
,
8
,
11
,
20
)
]
class FPS:
STATS_UPDATE_FREQUENCY
= CLOCK_SPEED.
TICKS_PER_SECOND
诸如2to3和Pyflakes之类的自动化工具无法检测到问题,但是Python 3不会将GAME_SPEED.TICKS_PER_SECOND视为有效的语句,因为从未明确声明要调用的函数。 调整代码是面向对象编程中的一个简单练习:
class CLOCK_SPEED:
def TICKS_PER_SECOND
(
) :
TICKS_PER_SECOND
=
16
TICK_RATES
=
[
int
( i * TICKS_PER_SECOND
)
for i
in
(
0.5
,
1
,
2
,
3
,
4
,
6
,
8
,
11
,
20
)
]
return TICKS_PER_SECOND
class FPS:
STATS_UPDATE_FREQUENCY
= CLOCK_SPEED.
TICKS_PER_SECOND
(
)
您可能倾向于通过使用构造函数替换TICKS_PER_SECOND函数(使用__init__函数来设置默认值)来使其更加干净,但这可能会将所需的调用从CLOCK_SPEED.TICKS_PER_SECOND()更改为CLOCK_SPEED() ,这可能会在代码库的其他地方没有分支。 如果您很了解代码,则可以更好地判断
需要多少,多少会令人愉悦,但是总的来说,我倾向于假设我所做的每项更改都不可避免地需要对项目中的每个其他文件至少进行三项更改,因此我尝试在其现有结构中工作。不要停止相信
如果您要移植一个非常大的项目,有时会感觉好像没有尽头。 在您看到有用的错误消息(似乎与Python 2怪胎无关地绕过脚本和lint)之前,这似乎永远存在,一旦到达这一点,您就会开始怀疑,从头开始会更容易。 好的一面是,您(大概)知道要移植的代码库在Python 2中可以工作(或可以工作),一旦进行了调整,它就可以在Python 3中再次工作。 这只是转换问题。
完成腿部工作后,您将拥有一个Python 3模块或应用程序,并且常规维护(以及那些使Pylint感到高兴的样式更改)可以重新开始!
翻译自: https://opensource.com/article/19/12/update-apps-python-3
python 应用程序