2to3 — 自动化 Python 2 到 3 代码转换¶
2to3 是一个 Python 程序,它读取 Python 2.x 源代码并应用一系列修复程序将其转换为有效的 Python 3.x 代码。标准库包含一组丰富的修复程序,几乎可以处理所有代码。2to3 支持库 lib2to3 然而,是一个灵活且通用的库,因此可以为 2to3 编写自己的修复程序。
自 3.11 版弃用,将在 3.13 版中移除: lib2to3 模块在 Python 3.9 中标记为待弃用(导入时引发 PendingDeprecationWarning)并在 Python 3.11 中完全弃用(引发 DeprecationWarning)。2to3 工具是其中的一部分。它将在 Python 3.13 中移除。
使用 2to3¶
2to3 通常会作为脚本与 Python 解释器一起安装。它还位于 Python 根目录的 Tools/scripts 目录中。
2to3 的基本参数是要转换的文件或目录列表。目录将递归遍历以查找 Python 源代码。
以下是一个示例 Python 2.x 源文件 example.py
def greet(name):
print "Hello, {0}!".format(name)
print "What's your name?"
name = raw_input()
greet(name)
可以通过命令行上的 2to3 将其转换为 Python 3.x 代码
$ 2to3 example.py
将打印与原始源文件相比的差异。2to3 还可以将所需的修改直接写入源文件。(除非还给出了 -n,否则将备份原始文件。)使用 -w 标志启用将更改写回
$ 2to3 -w example.py
转换后,example.py 如下所示
def greet(name):
print("Hello, {0}!".format(name))
print("What's your name?")
name = input()
greet(name)
在整个转换过程中保留注释和确切缩进。
默认情况下,2to3 运行一组 预定义修复程序。 -l 标志列出所有可用的修复程序。可以使用 -f 给出要运行的明确修复程序集。同样, -x 明确禁用修复程序。以下示例仅运行 imports 和 has_key 修复程序
$ 2to3 -f imports -f has_key example.py
此命令运行除 apply 修复程序之外的每个修复程序
$ 2to3 -x apply example.py
某些修复程序是显式的,这意味着它们不会默认运行,并且必须在命令行中列出才能运行。此处,除了默认修复程序之外,还运行 idioms 修复程序
$ 2to3 -f all -f idioms example.py
请注意如何传递 all 启用所有默认修复程序。
有时,2to3 会在源代码中找到需要更改的位置,但 2to3 无法自动修复。在这种情况下,2to3 会在文件的 diff 下方打印警告。你应该解决警告以获得兼容的 3.x 代码。
2to3 还可以重构 doctest。要启用此模式,请使用 -d 标志。请注意,仅重构 doctest。这也并不需要模块是有效的 Python。例如,reST 文档中的类似 doctest 的示例也可以使用此选项进行重构。
-v 选项启用输出有关翻译过程的更多信息。
由于某些 print 语句可以解析为函数调用或语句,因此 2to3 并不总是可以读取包含 print 函数的文件。当 2to3 检测到 from __future__ import print_function 编译器指令的存在时,它会修改其内部语法以将 print() 解释为函数。此更改也可以使用 -p 标志手动启用。使用 -p 对其 print 语句已转换的代码运行修复程序。此外, -e 可用于使 exec() 成为函数。
-o 或 --output-dir 选项允许指定要将处理后的输出文件写入的备用目录。在不覆盖输入文件时,使用此选项时需要 -n 标志,因为备份文件没有意义。
在 3.2.3 版中添加: 添加了 -o 选项。
标志 -W 或 --write-unchanged-files 告知 2to3 始终写入输出文件,即使文件不需要任何更改。这与 -o 结合使用时最有用,这样便可将整个 Python 源代码树从一个目录复制到另一个目录,同时进行转换。此选项隐含标志 -w,否则它没有任何意义。
在版本 3.2.3 中添加: 添加了标志 -W。
选项 --add-suffix 指定要追加到所有输出文件名的字符串。指定此选项时需要标志 -n,因为写入不同文件名时不需要备份。示例
$ 2to3 -n -W --add-suffix=3 example.py
将导致写入一个名为 example.py3 的已转换文件。
在版本 3.2.3 中添加: 添加了选项 --add-suffix。
要将整个项目从一个目录树转换到另一个目录树,请使用
$ 2to3 --output-dir=python3-version/mycode -W -n python2-version/mycode
修复程序¶
转换代码的每个步骤都封装在一个修复程序中。命令 2to3 -l 会列出它们。如 上述文档 所述,每个修复程序都可以单独打开和关闭。此处将详细描述它们。
- apply¶
删除
apply()的用法。例如,apply(function, *args, **kwargs)转换为function(*args, **kwargs)。
- asserts¶
用正确的名称替换已弃用的
unittest方法名称。从
到
failUnlessEqual(a, b)assertEquals(a, b)failIfEqual(a, b)assertNotEquals(a, b)failUnless(a)assert_(a)failIf(a)failUnlessRaises(exc, cal)failUnlessAlmostEqual(a, b)assertAlmostEquals(a, b)failIfAlmostEqual(a, b)assertNotAlmostEquals(a, b)
- buffer¶
将
buffer转换为memoryview。此修复程序是可选的,因为memoryviewAPI 与buffer的 API 类似,但并不完全相同。
- dict¶
修复字典迭代方法。将
dict.iteritems()转换为dict.items(),将dict.iterkeys()转换为dict.keys(),将dict.itervalues()转换为dict.values()。类似地,将dict.viewitems()、dict.viewkeys()和dict.viewvalues()分别转换为dict.items()、dict.keys()和dict.values()。它还将dict.items()、dict.keys()和dict.values()的现有用法包装在对list的调用中。
- except¶
将
except X, T转换为except X as T。
- funcattrs¶
修复已重命名的函数属性。例如,
my_function.func_closure转换为my_function.__closure__。
- future¶
删除
from __future__ import new_feature语句。
- getcwdu¶
将
os.getcwdu()重命名为os.getcwd()。
- has_key¶
将
dict.has_key(key)更改为key in dict。
- idioms¶
此可选修复程序执行多项转换,使 Python 代码更符合惯用语。将
type(x) is SomeClass和type(x) == SomeClass等类型比较转换为isinstance(x, SomeClass)。while 1变成while True。此修复程序还尝试在适当的位置使用sorted()。例如,此块L = list(some_iterable) L.sort()
将更改为
L = sorted(some_iterable)
- import¶
检测同级导入并将其转换为相对导入。
- imports¶
处理标准库中的模块重命名。
- input¶
将
input(prompt)转换为eval(input(prompt))。
- intern¶
将
intern()转换为sys.intern()。
- isinstance¶
修复
isinstance()第二个参数中的重复类型。例如,isinstance(x, (int, int))转换为isinstance(x, int),isinstance(x, (int, float, int))转换为isinstance(x, (int, float))。
- itertools_imports¶
删除
itertools.ifilter()、itertools.izip()和itertools.imap()的导入。itertools.ifilterfalse()的导入也已更改为itertools.filterfalse()。
- itertools¶
更改对
itertools.ifilter()、itertools.izip()和itertools.imap()的使用,使其等效于其内置函数。将itertools.ifilterfalse()更改为itertools.filterfalse()。
- metaclass¶
将旧元类语法(类主体中的
__metaclass__ = Meta)转换为新语法(class X(metaclass=Meta))。
- methodattrs¶
修复旧方法属性名称。例如,将
meth.im_func转换为meth.__func__。
- ne¶
将旧的不等于语法
<>转换为!=。
- next¶
将迭代器的
next()方法的使用转换为next()函数。还将next()方法重命名为__next__()。
- nonzero¶
将名为
__nonzero__()的方法的定义重命名为__bool__()。
- numliterals¶
将八进制字面量转换为新语法。
- operator¶
将
operator模块中对各种函数的调用转换为其他等效的函数调用。在需要时,会添加适当的import语句,例如import collections.abc。进行以下映射从
到
operator.isCallable(obj)callable(obj)operator.sequenceIncludes(obj)operator.contains(obj)operator.isSequenceType(obj)isinstance(obj, collections.abc.Sequence)operator.isMappingType(obj)isinstance(obj, collections.abc.Mapping)operator.isNumberType(obj)isinstance(obj, numbers.Number)operator.repeat(obj, n)operator.mul(obj, n)operator.irepeat(obj, n)operator.imul(obj, n)
- paren¶
在列表解析中需要的地方添加额外的括号。例如,
[x for x in 1, 2]变为[x for x in (1, 2)]。
- raise¶
将
raise E, V转换为raise E(V),将raise E, V, T转换为raise E(V).with_traceback(T)。如果E是一个元组,则转换将不正确,因为在 3.0 中已删除将元组替换为异常的做法。
- reduce¶
处理
reduce()移至functools.reduce()。
- reload¶
将
reload()转换为importlib.reload()。
- renames¶
将
sys.maxint更改为sys.maxsize。
- sys_exc¶
将已弃用的
sys.exc_value、sys.exc_type、sys.exc_traceback更改为使用sys.exc_info()。
- throw¶
修复生成器的
throw()方法中的 API 更改。
- tuple_params¶
删除隐式元组参数解包。此修复程序插入临时变量。
- ws_comma¶
从逗号分隔项中移除多余的空白。此修复程序是可选的。
- xreadlines¶
将
for x in file.xreadlines()更改为for x in file。
lib2to3 — 2to3 的库¶
源代码: Lib/lib2to3/
自 3.11 版本弃用,将在 3.13 版本中移除: Python 3.9 切换到了 PEG 解析器(参见 PEP 617),而 lib2to3 则使用灵活性较低的 LL(1) 解析器。Python 3.10 包含 lib2to3 的 LL(1) 解析器无法解析的新语言语法(参见 PEP 634)。lib2to3 模块在 Python 3.9 中被标记为待弃用(在导入时引发 PendingDeprecationWarning),并在 Python 3.11 中完全弃用(引发 DeprecationWarning)。它将在 Python 3.13 中从标准库中移除。考虑使用第三方替代方案,例如 LibCST 或 parso。
注意
lib2to3 API 应被视为不稳定,未来可能会发生巨大变化。