25.4. 2to3 - Python 2 から 3 への自動コード変換¶
2to3 は、 Python 2.x のソースコードを読み込み、一連の 変換プログラム を適用して Python 3.x のコードに変換するプログラムです。標準ライブラリはほとんど全てのコードを取り扱うのに十分な変換プログラムを含んでいます。ただし 2to3 を構成している lib2to3 は柔軟かつ一般的なライブラリなので、 2to3 のために自分で変換プログラムを書くこともできます。 lib2to3 は、 Python コードを自動編集する必要がある場合にも適用することができます。
25.4.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 フラグが要ります。
バージョン 2.7.3 で追加: -o オプションが追加されました。
-W または --write-unchanged-files により、たとえファイルに変更が必要なくても常にファイルを出力するように 2to3 に指示することが出来ます。これは、 -o とともに使って、Python ソースツリー全体を変換して別のディレクトリに書き出す際に最も有用です。
バージョン 2.7.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 として書き出されます。
バージョン 2.7.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
25.4.2. 変換プログラム¶
コード変形の各ステップは変換プログラムに隠蔽されます。 2to3 -l コマンドは変換プログラムのリストを表示します。 上記 の通り、それぞれの変換プログラムを個別に有効化したり無効化したりすることができます。ここではそれらをさらに詳細に説明します。
-
asserts¶ 廃止になった
unittestメソッド名を新しい名前に置換します。対象
変換先
failUnlessEqual(a, b)assertEquals(a, b)failIfEqual(a, b)assertNotEquals(a, b)failUnless(a)assert_(a)failIf(a)failUnlessRaises(exc, cal)failUnlessAlmostEqual(a, b)assertAlmostEquals(a, b)failIfAlmostEqual(a, b)assertNotAlmostEquals(a, b)
-
basestring¶ basestringをstrに変換します。
-
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に変換します。
-
execfile¶ execfile()の使用を削除します。execfile()への引数はopen(),compile(),exec()の呼び出しでラップされます。
-
exitfunc¶ sys.exitfuncへの代入をatexitモジュールの使用に変更します。
-
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))に変換します。
-
isinstance¶ isinstance()の第 2 引数の重複を修正します。例えば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()に変換されます。
-
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¶ 古い不等号の構文
<>を!=に変換します。
-
nonzero¶ __nonzero__()を__bool__()に変更します。
-
numliterals¶ 8 進数リテラルを新しい構文に変換します。
-
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)に変換します。例外の代わりにタプルを使用することは Python 3 で削除されたので、Eがタプルならこの変換は不正確になります。
-
raw_input¶ raw_input()をinput()に変換します。
-
reduce¶ reduce()がfunctools.reduce()に移動されたことを扱います。
-
renames¶ sys.maxintをsys.maxsizeに変更します。
-
standarderror¶ StandardErrorをExceptionに変更します。
-
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に変更します。
