# 26.7. 2to3 - Python 2 から 3 への自動コード変換

2to3 は、 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 は一連の 事前定義された変換プログラム を実行します。 `-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 はファイルの変更点の下に警告を表示します。 3.x に準拠したコードにするために、あなたはこの警告に対処しなくてはなりません。

2to3 は doctest の修正もできます。このモードを有効化するには `-d` フラグを指定して下さい。 doctest だけ が修正されることに注意して下さい。これは、モジュールが有効な Python コードであることを要求しないということでもあります。例えば、 reST ドキュメント中の doctest に似たサンプルコードなども、このオプションで修正することができます。

`-v` は、変換処理のより詳しい情報の出力を有効化します。

いくつかの print 文は関数呼び出しとしても文としても解析できるので、 2to3 は print 関数を含むファイルを常に読めるとは限りません。 2to3 は `from __future__ import print_function` コンパイラディレクティブが存在することを検出すると、内部の文法を変更して `print()` を関数として解釈するようになります。 `-p` フラグによって手動でこの変更を有効化することもできます。 print 文を変換済みのコードに対して変換プログラムを適用するには `-p` を使用してください。

`-o` または `--output-dir` で処理結果の出力先ディレクトリを変更出来ます。入力ファイルを上書きしないならバックアップは意味をなさないので、オプション `-n` フラグが要ります。

バージョン 3.2.3 で追加: `-o` オプションが追加されました。

`-W` または `--write-unchanged-files` により、たとえファイルに変更が必要なくても常にファイルを出力するように 2to3 に指示することが出来ます。これは、 `-o` とともに使って、Python ソースツリー全体を変換して別のディレクトリに書き出す際に最も有用です。

バージョン 3.2.3 で追加: The `-W` flag was added.

The `--add-suffix` option specifies a string to append to all output filenames. The `-n` flag is required when specifying this as backups are not necessary when writing to different filenames. Example:

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

とすれば変換後ファイルは `example.py3` として書き出されます。

バージョン 3.2.3 で追加: The `--add-suffix` option was added.

To translate an entire project from one directory tree to another use:

    $ 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` メソッド名を新しい名前に置換します。

  対象 | 変換先
  --- | ---
  `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` と似ているものの厳密に同じではないので、この変換プログラムはオプションです。

`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 コードをより 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`

  暗黙の相対インポート (sibling imports) を検出して、明示的な相対インポート (relative imports) に変換します。

`imports`

  標準ライブラリ中のモジュール名の変更を扱います。

`imports2`

  標準ライブラリ中の別のモジュール名の変更を扱います。単に技術的な制約のために `imports` とは別になっています。

`input`

  `input(prompt)` を `eval(input(prompt))` に変換します。

`intern`

  `intern()` を `sys.intern()` に変換します。

`isinstance`

  Fixes duplicate types in the second argument of `isinstance()`. For example, `isinstance(x, (int, int))` is converted to `isinstance(x, int)` and `isinstance(x, (int, float, int))` is converted to `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()` に変換されます。

`long`

  `long` を `int` に変更します。

`map`

  `list` 呼び出しの中の `map()` をラップします。また、 `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`

  8 進数リテラルを新しい構文に変換します。

`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)` に変換します。例外の代わりにタプルを使用することは 3.0 で削除されたので、`E` がタプルならこの変換は不正確になります。

`raw_input`

  `raw_input()` を `input()` に変換します。

`reduce`

  `reduce()` が `functools.reduce()` に移動されたことを扱います。

`reload`

  `reload()` を `imp.reload()` に変換します。

`renames`

  `sys.maxint` を `sys.maxsize` に変更します。

`repr`

  バッククォートを使った repr を `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()` に変更して、既存の `range()` 呼び出しを `list` でラップします。

`xreadlines`

  `for x in file.xreadlines()` を `for x in file` に変更します。

`zip`

  `list` 呼び出しの中で使われている `zip()` をラップします。これは `from future_builtins import zip` が見つかった場合は無効にされます。

## 26.7.3. `lib2to3` - 2to3's library

ソースコード: Lib/lib2to3/

注釈

`lib2to3` API は安定しておらず、将来、劇的に変更されるかも知れないと考えるべきです。