2to3 は、 Python 2.x のソースコードを読み込み、一連の 変換プログラム を適用して Python 3.x のコードに変換するプログラムです。標準ライブラリはほとんど全てのコードを取り扱うのに十分な変換プログラムを含んでいます。ただし 2to3 を構成している lib2to3 は柔軟かつ一般的なライブラリなので、 2to3 のために自分で変換プログラムを書くこともできます。 lib2to3 は、 Python コードを自動編集する必要がある場合にも適用することができます。
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 は必要となる変更をソースファイルに書き込むこともできます (もちろんオリジナルのバックアップも作成されます)。変更の書き戻しは -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 フラグにより、実行する変換プログラムを明示的に与えることもできます。下記の例では、 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 を使用してください。
コード変形の各ステップは変換プログラムに隠蔽されます。 2to3 -l コマンドは変換プログラムのリストを表示します。 上記 の通り、それぞれの変換プログラムを個別に有効化したり無効化したりすることができます。ここではそれらをさらに詳細に説明します。
basestring を str に変換します。
callable(x) を isinstance(x, collections.Callable) に変換し、必要なら collections のインポートを追加します。
辞書をイテレートするメソッドを修正します。 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 X, T を except X as T に変換します。
execfile() の使用を削除します。 execfile() への引数は open(), compile(), exec() の呼び出しでラップされます。
sys.exitfunc への代入を atexit モジュールの使用に変更します。
名前が変更された関数の属性を修正します。例えば my_function.func_closure は my_function.__closure__ に変換されます。
from __future__ import new_feature 文を削除します。
os.getcwdu() を os.getcwd() に置き換えます。
dict.has_key(key) を key in dict に変更します。
このオプションの変換プログラムは、 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)
暗黙の相対インポート (sibling imports) を検出して、明示的な相対インポート (relative imports) に変換します。
標準ライブラリ中のモジュール名の変更を扱います。
input(prompt) を eval(input(prompt)) に変換します。
isinstance() の第 2 引数の重複を修正します。例えば isinstance(x, (int, int)) は isinstance(x, (int)) に変換されます。
itertools.ifilter(), itertools.izip(), itertools.imap() のインポートを削除します。また itertools.ifilterfalse() のインポートを itertools.filterfalse() に変換します。
itertools.ifilter(), itertools.izip(), itertools.imap() を使っている箇所を同等の組み込み関数で置き換えます。 itertools.ifilterfalse() は itertools.filterfalse() に変換されます。
list 呼び出しの中の map() をラップします。また、 map(None, x) を list(x) に変換します。 from future_builtins import map を使うと、この変換プログラムを無効にできます。
古いメタクラス構文 (クラス定義中の __metaclass__ = Meta) を、新しい構文 (class X(metaclass=Meta)) に変換します。
古いメソッドの属性名を修正します。例えば meth.im_func は meth.__func__ に変換されます。
古い不等号の構文 <> を != に変換します。
__nonzero__() を __bool__() に変更します。
8進数リテラルを新しい構文に変換します。
リスト内包表記で必要になる括弧を追加します。例えば [x for x in 1, 2] は [x for x in (1, 2)] になります。
raise E, V を raise E(V) に、 raise E, V, T を raise E(V).with_traceback(T) に変換します。例外の代わりにタプルを使用することは 3.0 で削除されたので、 E がタプルならこの変換は不正確になります。
raw_input() を input() に変換します。
reduce() が functools.reduce() に移動されたことを扱います。
sys.maxint を sys.maxsize に変更します。
StandardError を Exception に変更します。
廃止された sys.exc_value, sys.exc_type, sys.exc_traceback の代わりに sys.exc_info() を使うように変更します。
ジェネレータの throw() メソッドの API 変更を修正します。
関数定義における暗黙的なタプルパラメータの展開を取り除きます。この変換プログラムによって一時変数が追加されます。
コンマ区切りの要素から余計な空白を取り除きます。この変換プログラムはオプションです。
for x in file.xreadlines() を for x in file に変更します。