> **Источник:** https://python-all.ru/2.7/library/2to3.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 25.4. 2to3 – автоматическое преобразование кода Python 2 в 3

2to3 – это программа на Python, которая читает исходный код Python 2.x и применяет серию *преобразователей* для преобразования его в корректный код Python 3.x. Стандартная библиотека содержит богатый набор преобразователей, которые справятся почти с любым кодом. 2to3 – поддерживающая библиотека [`lib2to3`](https://python-all.ru/2.7/library/2to3.html#module-lib2to3), однако, представляет собой гибкую и обобщённую библиотеку, поэтому можно написать собственные преобразователи для 2to3. [`lib2to3`](https://python-all.ru/2.7/library/2to3.html#module-lib2to3) также можно адаптировать для пользовательских приложений, в которых требуется редактировать код Python автоматически.

## 25.4.1. Использование 2to3

2to3 обычно устанавливается вместе с интерпретатором Python как скрипт. Он также находится в каталоге `Tools/scripts` корневой директории Python.

Основные аргументы 2to3 – это список файлов или каталогов для преобразования. Каталоги обходятся рекурсивно в поисках исходников Python.

Вот пример исходного файла на Python 2.x, `example.py`:

```python
def greet(name):
    print "Hello, {0}!".format(name)
print "What's your name?"
name = raw_input()
greet(name)
```

Его можно преобразовать в код Python 3.x с помощью 2to3 в командной строке:

```console
$ 2to3 example.py
```

Выводится diff относительно исходного файла. 2to3 также может записать необходимые изменения прямо в исходный файл. (Резервная копия исходного файла создаётся, если только не указан `-n`.) Запись изменений обратно включается флагом `-w`:

```console
$ 2to3 -w example.py
```

После преобразования `example.py` выглядит так:

```python
def greet(name):
    print("Hello, {0}!".format(name))
print("What's your name?")
name = input()
greet(name)
```

Комментарии и точные отступы сохраняются на протяжении всего процесса преобразования.

По умолчанию 2to3 запускает набор [предопределённых преобразователей](https://python-all.ru/2.7/library/2to3.html#to3-fixers). Флаг `-l` выводит список всех доступных преобразователей. Явный набор преобразователей для запуска можно задать с помощью `-f`. Аналогично `-x` явно отключает преобразователь. В следующем примере запускаются только преобразователи `imports` и `has_key`:

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

Эта команда запускает все преобразователи, кроме `apply`:

```console
$ 2to3 -x apply example.py
```

Некоторые преобразователи являются *явными*, то есть они не запускаются по умолчанию и должны быть перечислены в командной строке для запуска. Здесь, помимо преобразователей по умолчанию, запускается преобразователь `idioms`:

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

Обратите внимание: передача `all` включает все преобразователи по умолчанию.

Иногда 2to3 находит в исходном коде место, которое нужно изменить, но не может исправить автоматически. В этом случае 2to3 выводит предупреждение под diff для файла. Следует обработать это предупреждение, чтобы получить корректный код 3.x.

2to3 также может рефакторить доктесты. Чтобы включить этот режим, используйте флаг `-d`. Обратите внимание, что рефакторингу подвергнутся *только* доктесты. Для этого также не требуется, чтобы модуль был корректным Python. Например, примеры, оформленные как доктесты в reST-документе, также могут быть отрефакторены с помощью этой опции.

Опция `-v` включает вывод дополнительной информации о процессе преобразования.

Поскольку некоторые операторы print можно разобрать как вызовы функций или инструкции, 2to3 не всегда может читать файлы, содержащие функцию print. Когда 2to3 обнаруживает наличие директивы компилятора `from __future__ import print_function`, он изменяет свою внутреннюю грамматику, чтобы интерпретировать [`print()`](https://python-all.ru/2.7/library/functions.html#print) как функцию. Это изменение также можно включить вручную с помощью флага `-p`. Используйте `-p` для запуска преобразователей на коде, в котором операторы print уже преобразованы.

Опция `-o` или `--output-dir` позволяет указать альтернативный каталог для записи выходных файлов. Флаг `-n` обязателен при использовании этого, поскольку резервные копии не имеют смысла, когда исходные файлы не перезаписываются.

Новое в версии 2.7.3: Добавлена опция `-o`.

Флаг `-W` или `--write-unchanged-files` предписывает 2to3 всегда записывать выходные файлы, даже если файл не требовал изменений. Это наиболее полезно с `-o`, чтобы всё дерево исходников Python было скопировано с преобразованием из одного каталога в другой. Эта опция подразумевает флаг `-w`, иначе она не имела бы смысла.

Новое в версии 2.7.3: Добавлен флаг `-W`.

Опция `--add-suffix` задаёт строку, которая будет добавлена ко всем именам выходных файлов. Флаг `-n` обязателен при указании этой опции, так как резервные копии не нужны при записи в файлы с другими именами. Пример:

```console
$ 2to3 -n -W --add-suffix=3 example.py
```

Приведёт к записи преобразованного файла с именем `example.py3`.

Новое в версии 2.7.3: Добавлена опция `--add-suffix`.

Чтобы преобразовать весь проект из одного дерева каталогов в другое, используйте:

```console
$ 2to3 --output-dir=python3-version/mycode -W -n python2-version/mycode
```

## 25.4.2. Исправители

Каждый шаг преобразования кода инкапсулирован в преобразователе. Команда `2to3 -l` выводит их список. Как [описано выше](https://python-all.ru/2.7/library/2to3.html#to3-using), каждый можно включать и отключать по отдельности. Здесь они описаны более подробно.

**`apply`**

Удаляет использование [`apply()`](https://python-all.ru/2.7/library/functions.html#apply). Например, `apply(function, *args, **kwargs)` преобразуется в `function(*args, **kwargs)`.

**`asserts`**

Заменяет устаревшие имена методов [`unittest`](https://python-all.ru/2.7/library/unittest.html#module-unittest) на корректные.

| Из | В |
| --- | --- |
| `failUnlessEqual(a, b)` | [`assertEqual(a, b)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertEqual) |
| `assertEquals(a, b)` | [`assertEqual(a, b)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertEqual) |
| `failIfEqual(a, b)` | [`assertNotEqual(a, b)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertNotEqual) |
| `assertNotEquals(a, b)` | [`assertNotEqual(a, b)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertNotEqual) |
| `failUnless(a)` | [`assertTrue(a)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertTrue) |
| `assert_(a)` | [`assertTrue(a)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertTrue) |
| `failIf(a)` | [`assertFalse(a)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertFalse) |
| `failUnlessRaises(exc, cal)` | [`assertRaises(exc, cal)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertRaises) |
| `failUnlessAlmostEqual(a, b)` | [`assertAlmostEqual(a, b)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertAlmostEqual) |
| `assertAlmostEquals(a, b)` | [`assertAlmostEqual(a, b)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertAlmostEqual) |
| `failIfAlmostEqual(a, b)` | [`assertNotAlmostEqual(a, b)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertNotAlmostEqual) |
| `assertNotAlmostEquals(a, b)` | [`assertNotAlmostEqual(a, b)`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase.assertNotAlmostEqual) |

**`basestring`**

Преобразует [`basestring`](https://python-all.ru/2.7/library/functions.html#basestring) в [`str`](https://python-all.ru/2.7/library/functions.html#str).

**`buffer`**

Преобразует [`buffer`](https://python-all.ru/2.7/library/functions.html#buffer) в [`memoryview`](https://python-all.ru/2.7/library/stdtypes.html#memoryview). Этот фиксер необязателен, поскольку API [`memoryview`](https://python-all.ru/2.7/library/stdtypes.html#memoryview) похож, но не полностью совпадает с API [`buffer`](https://python-all.ru/2.7/library/functions.html#buffer).

**`dict`**

Исправляет методы итерации словарей. [`dict.iteritems()`](https://python-all.ru/2.7/library/stdtypes.html#dict.iteritems) преобразуется в [`dict.items()`](https://python-all.ru/2.7/library/stdtypes.html#dict.items), [`dict.iterkeys()`](https://python-all.ru/2.7/library/stdtypes.html#dict.iterkeys) – в [`dict.keys()`](https://python-all.ru/2.7/library/stdtypes.html#dict.keys), а [`dict.itervalues()`](https://python-all.ru/2.7/library/stdtypes.html#dict.itervalues) – в [`dict.values()`](https://python-all.ru/2.7/library/stdtypes.html#dict.values). Аналогично, [`dict.viewitems()`](https://python-all.ru/2.7/library/stdtypes.html#dict.viewitems), [`dict.viewkeys()`](https://python-all.ru/2.7/library/stdtypes.html#dict.viewkeys) и [`dict.viewvalues()`](https://python-all.ru/2.7/library/stdtypes.html#dict.viewvalues) преобразуются соответственно в [`dict.items()`](https://python-all.ru/2.7/library/stdtypes.html#dict.items), [`dict.keys()`](https://python-all.ru/2.7/library/stdtypes.html#dict.keys) и [`dict.values()`](https://python-all.ru/2.7/library/stdtypes.html#dict.values). Также он оборачивает существующие использования [`dict.items()`](https://python-all.ru/2.7/library/stdtypes.html#dict.items), [`dict.keys()`](https://python-all.ru/2.7/library/stdtypes.html#dict.keys) и [`dict.values()`](https://python-all.ru/2.7/library/stdtypes.html#dict.values) в вызов `list`.

**`except`**

Преобразует `except X, T` в `except X as T`.

**`exec`**

Преобразует инструкцию [`exec`](https://python-all.ru/2.7/reference/simple_stmts.html#exec) в функцию `exec()`.

**`execfile`**

Удаляет использование [`execfile()`](https://python-all.ru/2.7/library/functions.html#execfile). Аргумент [`execfile()`](https://python-all.ru/2.7/library/functions.html#execfile) оборачивается в вызовы [`open()`](https://python-all.ru/2.7/library/functions.html#open), [`compile()`](https://python-all.ru/2.7/library/functions.html#compile) и `exec()`.

**`exitfunc`**

Изменяет присваивание [`sys.exitfunc`](https://python-all.ru/2.7/library/sys.html#sys.exitfunc) на использование модуля [`atexit`](https://python-all.ru/2.7/library/atexit.html#module-atexit).

**`filter`**

Оборачивает использование [`filter()`](https://python-all.ru/2.7/library/functions.html#filter) в вызов `list`.

**`funcattrs`**

Исправляет переименованные атрибуты функций. Например, `my_function.func_closure` преобразуется в `my_function.__closure__`.

**`future`**

Удаляет операторы `from __future__ import new_feature`.

**`getcwdu`**

Переименовывает [`os.getcwdu()`](https://python-all.ru/2.7/library/os.html#os.getcwdu) в [`os.getcwd()`](https://python-all.ru/2.7/library/os.html#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()`](https://python-all.ru/2.7/library/functions.html#sorted) в подходящих местах. Например, этот блок

```python
L = list(some_iterable)
L.sort()
```

изменяется на

```python
L = sorted(some_iterable)
```

**`import`**

Обнаруживает импорты соседних модулей и преобразует их в относительные импорты.

**`imports`**

Обрабатывает переименования модулей в стандартной библиотеке.

**`imports2`**

Обрабатывает переименования других модулей в стандартной библиотеке. Он отделён от фиксера [`imports`](https://python-all.ru/2.7/library/2to3.html#2to3fixer-imports) только из-за технических ограничений.

**`input`**

Преобразует `input(prompt)` в `eval(input(prompt))`.

**`intern`**

Преобразует [`intern()`](https://python-all.ru/2.7/library/functions.html#intern) в `sys.intern()`.

**`isinstance`**

Исправляет дублирование типов во втором аргументе [`isinstance()`](https://python-all.ru/2.7/library/functions.html#isinstance). Например, `isinstance(x, (int, int))` преобразуется в `isinstance(x, (int))`.

**`itertools_imports`**

Удаляет импорты [`itertools.ifilter()`](https://python-all.ru/2.7/library/itertools.html#itertools.ifilter), [`itertools.izip()`](https://python-all.ru/2.7/library/itertools.html#itertools.izip) и [`itertools.imap()`](https://python-all.ru/2.7/library/itertools.html#itertools.imap). Импорты [`itertools.ifilterfalse()`](https://python-all.ru/2.7/library/itertools.html#itertools.ifilterfalse) также заменяются на `itertools.filterfalse()`.

**`itertools`**

Изменяет использование [`itertools.ifilter()`](https://python-all.ru/2.7/library/itertools.html#itertools.ifilter), [`itertools.izip()`](https://python-all.ru/2.7/library/itertools.html#itertools.izip) и [`itertools.imap()`](https://python-all.ru/2.7/library/itertools.html#itertools.imap) на их встроенные аналоги. [`itertools.ifilterfalse()`](https://python-all.ru/2.7/library/itertools.html#itertools.ifilterfalse) заменяется на `itertools.filterfalse()`.

**`long`**

Переименовывает [`long`](https://python-all.ru/2.7/library/functions.html#long) в [`int`](https://python-all.ru/2.7/library/functions.html#int).

**`map`**

Оборачивает [`map()`](https://python-all.ru/2.7/library/functions.html#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()`](https://python-all.ru/2.7/library/stdtypes.html#iterator.next) итератора в функцию [`next()`](https://python-all.ru/2.7/library/functions.html#next). Также переименовывает методы [`next()`](https://python-all.ru/2.7/library/stdtypes.html#iterator.next) в `__next__()`.

**`nonzero`**

Переименовывает [`__nonzero__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__nonzero__) в `__bool__()`.

**`numliterals`**

Преобразует восьмеричные литералы в новый синтаксис.

**`paren`**

Добавляет дополнительные круглые скобки там, где они необходимы в списковых включениях. Например, `[x for x in 1, 2]` становится `[x for x in (1, 2)]`.

**`print`**

Преобразует инструкцию [`print`](https://python-all.ru/2.7/reference/simple_stmts.html#print) в функцию [`print()`](https://python-all.ru/2.7/library/functions.html#print).

**`raise`**

Преобразует `raise E, V` в `raise E(V)`, а `raise E, V, T` в `raise E(V).with_traceback(T)`. Если `E` является кортежем, преобразование будет неверным, поскольку в Python 3 удалена подстановка кортежей на место исключений.

**`raw_input`**

Преобразует [`raw_input()`](https://python-all.ru/2.7/library/functions.html#raw_input) в [`input()`](https://python-all.ru/2.7/library/functions.html#input).

**`reduce`**

Обрабатывает перемещение [`reduce()`](https://python-all.ru/2.7/library/functions.html#reduce) в [`functools.reduce()`](https://python-all.ru/2.7/library/functools.html#functools.reduce).

**`renames`**

Заменяет [`sys.maxint`](https://python-all.ru/2.7/library/sys.html#sys.maxint) на [`sys.maxsize`](https://python-all.ru/2.7/library/sys.html#sys.maxsize).

**`repr`**

Заменяет repr с обратными кавычками на функцию [`repr()`](https://python-all.ru/2.7/library/functions.html#repr).

**`set_literal`**

Заменяет использование конструктора [`set`](https://python-all.ru/2.7/library/stdtypes.html#set) на литералы множества. Этот фиксер является необязательным.

**`standarderror`**

Переименовывает [`StandardError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.StandardError) в [`Exception`](https://python-all.ru/2.7/library/exceptions.html#exceptions.Exception).

**`sys_exc`**

Изменяет устаревшие [`sys.exc_value`](https://python-all.ru/2.7/library/sys.html#sys.exc_value), [`sys.exc_type`](https://python-all.ru/2.7/library/sys.html#sys.exc_type), [`sys.exc_traceback`](https://python-all.ru/2.7/library/sys.html#sys.exc_traceback) на использование [`sys.exc_info()`](https://python-all.ru/2.7/library/sys.html#sys.exc_info).

**`throw`**

Исправляет изменение API в методе `throw()` генератора.

**`tuple_params`**

Удаляет неявную распаковку параметров кортежа. Этот фиксер вставляет временные переменные.

**`types`**

Исправляет код, сломанный в результате удаления некоторых членов модуля [`types`](https://python-all.ru/2.7/library/types.html#module-types).

**`unicode`**

Переименовывает [`unicode`](https://python-all.ru/2.7/library/functions.html#unicode) в [`str`](https://python-all.ru/2.7/library/functions.html#str).

**`urllib`**

Обрабатывает переименование [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib) и [`urllib2`](https://python-all.ru/2.7/library/urllib2.html#module-urllib2) в пакет [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib).

**`ws_comma`**

Удаляет лишние пробелы из элементов, разделённых запятыми. Этот фиксер необязателен.

**`xrange`**

Переименовывает [`xrange()`](https://python-all.ru/2.7/library/functions.html#xrange) в [`range()`](https://python-all.ru/2.7/library/functions.html#range) и оборачивает существующие вызовы [`range()`](https://python-all.ru/2.7/library/functions.html#range) в `list`.

**`xreadlines`**

Заменяет `for x in file.xreadlines()` на `for x in file`.

**`zip`**

Оборачивает использование [`zip()`](https://python-all.ru/2.7/library/functions.html#zip) в вызов `list`. Отключается, когда появляется `from future_builtins import zip`.

## 25.4.3. [`lib2to3`](https://python-all.ru/2.7/library/2to3.html#module-lib2to3) – библиотека 2to3

> **Примечание**
>
> API [`lib2to3`](https://python-all.ru/2.7/library/2to3.html#module-lib2to3) следует считать нестабильным; в будущем оно может кардинально измениться.
