Skip to main content

26.7. 2to3 - 自动化Python 2到3代码翻译

2to3是一个Python程序,它读取Python 2.x源代码,并应用一系列 fixers 将其转换为有效的Python 3.x代码。标准库包含一组丰富的修复程序,它们将处理几乎所有的代码。 2to3支持库 lib2to3 是一个灵活的通用库,因此可以为2to3编写自己的修复软件。 lib2to3 还可以适用于需要自动编辑Python代码的自定义应用程序。

26.7.1. 使用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 显式禁用修复程序。以下示例仅运行 importshas_key 修订程序:

$ 2to3 -f imports -f has_key example.py

此命令运行除 apply 修复程序之外的每个修复程序:

$ 2to3 -x apply example.py

一些修复程序是 explicit,意味着它们不是默认运行的,并且必须在命令行上列出以运行。在这里,除了默认修复程序,idioms 修复程序运行:

$ 2to3 -f all -f idioms example.py

注意传递 all 如何启用所有默认修复程序。

有时2to3会在你的源代码中找到一个需要改变的地方,但2to3不能自动修复。在这种情况下,2to3将打印一个文件diff下面的警告。您应该解决该警告,以具有兼容的3.x代码。

2to3也可以重构doctests。要启用此模式,请使用 -d 标志。注意,only doctests将被重构。这也不需要模块是有效的Python。例如,doctest like reST文档中的示例也可以使用此选项重构。

-v 选项使得能够输出关于翻译过程的更多信息。

由于一些打印语句可以解析为函数调用或语句,因此2to3不能总是读取包含打印函数的文件。当2to3检测到 from __future__ import print_function 编译器指令的存在时,它修改其内部语法以将 print() 解释为函数。也可以使用 -p 标志手动启用此更改。使用 -p 在已经转换其打印语句的代码上运行修复程序。

-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

26.7.2. 固定器

转换代码的每个步骤都封装在固定器中。命令 2to3 -l 列出它们。作为 上面记录,每个可以单独打开和关闭。这里将更详细地描述它们。

apply

删除 apply() 的使用。例如,apply(function, *args, **kwargs) 被转换为 function(*args, **kwargs)

asserts

使用正确的 unittest 方法名称替换已弃用的 unittest 方法名称。

failUnlessEqual(a, b)

assertEqual(a, b)

assertEquals(a, b)

assertEqual(a, b)

failIfEqual(a, b)

assertNotEqual(a, b)

assertNotEquals(a, b)

assertNotEqual(a, b)

failUnless(a)

assertTrue(a)

assert_(a)

assertTrue(a)

failIf(a)

assertFalse(a)

failUnlessRaises(exc, cal)

assertRaises(exc, cal)

failUnlessAlmostEqual(a, b)

assertAlmostEqual(a, b)

assertAlmostEquals(a, b)

assertAlmostEqual(a, b)

failIfAlmostEqual(a, b)

assertNotAlmostEqual(a, b)

assertNotAlmostEquals(a, b)

assertNotAlmostEqual(a, b)

basestring

basestring 转换为 str

buffer

buffer 转换为 memoryview。此修复程序是可选的,因为 memoryview API是类似的,但不完全相同的 buffer

callable

callable(x) 转换为 isinstance(x, collections.Callable),如果需要,将导入添加到 collections。注意 callable(x) 在Python 3.2中返回,所以如果你不打算支持Python 3.1,你可以禁用这个修复软件。

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()。它还包含了对 list 的调用中的 dict.items()dict.keys()dict.values() 的现有用法。

except

except X, T 转换为 except X as T

exec

exec 语句转换为 exec() 函数。

execfile

删除 execfile() 的使用。 execfile() 的参数包含在对 open()compile()exec() 的调用中。

exitfunc

更改 sys.exitfunc 使用 atexit 模块的分配。

filter

list 调用中包含 filter() 使用。

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 SomeClasstype(x) == SomeClass 被转换为 isinstance(x, SomeClass)while 1 变为 while True。此修复程序还尝试在适当的地方使用 sorted()。例如,这个块

L = list(some_iterable)
L.sort()

更改为

L = sorted(some_iterable)
import

检测兄弟导入,并将其转换为相对导入。

imports

在标准库中处理模块重命名。

imports2

处理标准库中的其他模块重命名。它与 imports 固定器分开,只因为技术限制。

input

input(prompt) 转换为 eval(input(prompt))

intern

intern() 转换为 sys.intern()

isinstance

修复 isinstance() 的第二个参数中的重复类型。例如,isinstance(x, (int, int)) 被转换为 isinstance(x, (int))

itertools_imports

删除 itertools.ifilter()itertools.izip()itertools.imap() 的导入。 itertools.ifilterfalse() 的进口也改为 itertools.filterfalse()

itertools

itertools.ifilter()itertools.izip()itertools.imap() 的用法更改为其内置等效项。 itertools.ifilterfalse() 变为 itertools.filterfalse()

long

long 重命名为 int

map

封装 map()list 调用中。它还将 map(None, x) 更改为 list(x)。使用 from future_builtins import map 禁用此修复程序。

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。进行以下映射:

operator.isCallable(obj)

hasattr(obj, '__call__')

operator.sequenceIncludes(obj)

operator.contains(obj)

operator.isSequenceType(obj)

isinstance(obj, collections.Sequence)

operator.isMappingType(obj)

isinstance(obj, collections.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)]

print

print 语句转换为 print() 函数。

raise

raise E, V 转换为 raise E(V),将 raise E, V, T 转换为 raise E(V).with_traceback(T)。如果 E 是一个元组,则翻译将是不正确的,因为在3.0中已经去除了元组中的异常。

raw_input

raw_input() 转换为 input()

reduce

处理 reduce()functools.reduce() 的移动。

reload

reload() 转换为 imp.reload()

renames

sys.maxint 更改为 sys.maxsize

repr

repr() 函数替换backtick repr。

set_literal

用set literal替换 set 构造函数的使用。此修订包是可选的。

standarderror

StandardError 重命名为 Exception

sys_exc

将已弃用的 sys.exc_valuesys.exc_typesys.exc_traceback 更改为使用 sys.exc_info()

throw

修正发生器 throw() 方法中的API变化。

tuple_params

删除隐式元组参数解包。此修订包插入临时变量。

types

修复由于删除 types 模块中的一些成员而导致的代码。

unicode

unicode 重命名为 str

urllib

处理 urlliburllib2 的重命名到 urllib 包。

ws_comma

从逗号分隔的项目中删除多余的空格。此修订包是可选的。

xrange

xrange() 重命名为 range(),并用 list 包装现有的 range() 调用。

xreadlines

for x in file.xreadlines() 更改为 for x in file

zip

list 调用中包含 zip() 使用。当 from future_builtins import zip 出现时,禁用此选项。

26.7.3. lib2to3 - 2to3的图书馆

源代码: Lib/lib2to3/


注解

lib2to3 API应被视为不稳定,并且将来可能会发生巨大变化。