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 で追加: -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メソッド名を新しい名前に置換します。- 対象 - 変換先 - 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)
- 
buffer¶
- bufferを- memoryviewに変換します。- memoryviewAPI は- 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に変換します。
- 
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¶
- 標準ライブラリ中のモジュール名の変更を扱います。 
- 
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)).
- 
itertools_imports¶
- itertools.ifilter(),- itertools.izip(),- itertools.imap()のインポートを削除します。また- itertools.ifilterfalse()のインポートを- itertools.filterfalse()に変換します。
- 
itertools¶
- itertools.ifilter(),- itertools.izip(),- itertools.imap()を使っている箇所を同等の組み込み関数で置き換えます。- itertools.ifilterfalse()は- itertools.filterfalse()に変換されます。
- 
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)]になります。
- 
raise¶
- raise E, Vを- raise E(V)に、- raise E, V, Tを- raise E(V).with_traceback(T)に変換します。例外の代わりにタプルを使用することは 3.0 で削除されたので、- Eがタプルならこの変換は不正確になります。
- 
reduce¶
- reduce()が- functools.reduce()に移動されたことを扱います。
- 
reload¶
- reload()を- imp.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に変更します。
26.7.3. lib2to3 - 2to3's library¶
ソースコード: Lib/lib2to3/
注釈
lib2to3 API は安定しておらず、将来、劇的に変更されるかも知れないと考えるべきです。
