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

2to3是一个Python程序，它读取Python 2.x源代码，并应用一系列修复器将其转换为有效的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运行一组predefined fixers。`-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也可以重构doctests。要启用此模式，请使用`-d`标志。请注意，只有 doctests将被重构。这也不需要模块是有效的Python。例如，doctest like reST文档中的示例也可以使用此选项重构。

`-v`选项允许输出有关翻译过程的更多信息。

由于一些打印语句可以解析为函数调用或语句，因此2to3不能总是读取包含打印函数的文件。当2to3检测到`来自 t> __未来__ 导入 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. Fixers

转换代码的每个步骤都封装在修复程序中。命令`2to3 -l` 列出它们。由于documented above，每个可以单独打开和关闭。这里更详细地描述它们。

`apply`

  删除`apply()`的使用。例如`apply（function， * args， ** kwargs）`转换为`函数（* args， ** kwargs）`。

`asserts`

  用正确的方法替换已弃用的`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()` is converted to `dict.items()`, `dict.iterkeys()` to `dict.keys()`, and `dict.itervalues()` to `dict.values()`. 同样，`dict.viewitems()`，`dict.viewkeys()`和`dict.viewvalues()`分别转换为`dict.items()`，`dict.keys()`和`dict.values()`。It also wraps existing usages of `dict.items()`, `dict.keys()`, and `dict.values()` in a call to `list`.

`except`

  Converts `except X, T` to `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`

  从 __未来__ 导入 new_feature语句中删除``

`getcwdu`

  将`os.getcwdu()`重命名为`os.getcwd()`。

`has_key`

  在 dict中将`dict.has_key(key)`更改为`键 。`

`idioms`

  这个可选的修复程序执行几个转换，使Python代码更惯用。Type comparisons like `type(x) is SomeClass` and `type(x) == SomeClass` are converted to `isinstance(x, SomeClass)`. `，而 1`成为`，而` 此修复程序还尝试在适当的地方使用`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`

  在`list`调用中换行`map()`。它还会更改`映射（无， x）`到`list(x)`使用`从 future_builtins 导入 地图`禁用此修复程序。

`metaclass`

  Converts the old metaclass syntax (`__metaclass__ = Meta` in the class body) to the new (`class X(metaclass=Meta)`).

`methodattrs`

  修复旧方法属性名称。例如，`meth.im_func`被转换为`meth.__func__`。

`ne`

  将旧的不等式语法`<>`转换为`!=`。

`next`

  将迭代器的`next()`方法转换为`next()`函数。它还将`next()`方法重命名为`__next__()`。

`nonzero`

  将`__nonzero__()`重命名为`__bool__()`。

`numliterals`

  将八进制字面值转换为新的语法。

`operator`

  将对`operator`模块中各种函数的调用转换为其他函数，但等价的函数调用。需要时，添加适当的`import`语句，例如 `import 容器`。进行以下映射：

  从 | 至
  --- | ---
  `operator.isCallable(obj)` | `hasattr（obj， '__ call __'）`
  `operator.sequenceIncludes(obj)` | `operator.contains(obj)`
  `operator.isSequenceType(obj)` | `isinstance（obj， 容器。序列）`
  `operator.isMappingType(obj)` | `isinstance（obj， 容器.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`

  在列表推导式中添加需要的括号。For example, `[x for x in 1, 2]` becomes `[x for x in (1, 2)]`.

`print`

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

`raise`

  转换`提高 E， V`至`提高 E V）`和`提高 E， V， / t7>到`提高 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字面值替换`set`构造函数的使用。此修订包是可选的。

`standarderror`

  将`StandardError`重命名为`Exception`。

`sys_exc`

  更改已弃用的`sys.exc_value`，`sys.exc_type`，`sys.exc_traceback`以使用`sys.exc_info()`。

`throw`

  修复生成器的`throw()`方法中的API更改。

`tuple_params`

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

`types`

  修复因删除`types`模块中的某些成员而导致的代码。

`unicode`

  将`unicode`重命名为`str`。

`urllib`

  处理`urllib`和`urllib2`的重命名为`urllib`包。

`ws_comma`

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

`xrange`

  将`xrange()`重新命名为`range()`并用`list`包装现有`range()`

`xreadlines`

  Changes `for x in file.xreadlines()` to `for x in file`.

`zip`

  在`list`调用中封装`zip()`使用。当出现`从 future_builtins import zip`时，

## 26.7.3. `lib2to3` - 2to3的库

源代码： Lib/lib2to3/

注意

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