第 3 回 移植に使えるユーティリティ その1

移植ユーティリティとしては Python 標準のものに加え、サードパーティ製のもの、プロジェクトが必要に応じて作成したもの (ここでは OpenStack 作成のものを紹介) 等、多くのユーティリティが提供されています。
裏を返せばやはりこれは結構面倒な作業であると言う事かもしれません。

ここでは Python 2 と Python 3 の違いを吸収したり、ソースコードを自動で変換してくれる移植ライブラリや変換ツールについて解説します。

【移植ライブラリ】

__future__ (python 標準のモジュール)

__future__ モジュールを以下の様にインポートすることで、Python 2 上で Python 3 の機能を利用できるようになります。

from __future__ import feature-name

future 文の定義は以下 URL を参照ください。
http://docs.python.jp/3.4/library/__future__.html?highlight=__future__#__future__ 

また、Python 2.7 では次の feature を使用できます。

 

  • division
    ‘/’ の結果を浮動小数点で返す。

 

  • absolute_import
    明示的な相対インポートのサポート。

 

  • print_function
    print() 関数を使用可能にする。

 

  • unicode_literals
    プレフィックスのない文字列リテラルを unicode とみなす。

six

six は、Python 2 と Python 3 の両方で動作するラッパーメソッドや定義を提供するライブラリです。例えば Python 2 と Python 3 で定義の異なるデータ型を six 経由で使用する事により同一の定義名で使えるようになります。
下記のコード例で言うと six.text_type を使用すると Python2 では unicode 型、Python3 では str 型で参照する事となります。因みに six と言う奇妙なライブラリ名は、Python 2 / 3 をサポートする事から 2 x 3 = 6 に由来するそうです。
参考: http://pythonhosted.org/six/

six は 800 行ほどの Python スクリプトです。以下の様に単に Python のバージョンを判定して処理の分岐を行っている部分もあります。

…
# Useful for very coarse version differentiation.
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3

if PY3:
    string_types = str,
    integer_types = int,
    class_types = type,
    text_type = str
    binary_type = bytes

    MAXSIZE = sys.maxsize
else:
    string_types = basestring,
    integer_types = (int, long)
    class_types = (type, types.ClassType)
    text_type = unicode
    binary_type = str
…

【変換ツール】

2to3 (Python 付属のツール)

2to3 は、Python 2 のソースコードを Python 3 用に一方通行で変換するツールです。そのため、変換後のコードは Python 2 では動作しない可能性があります。2to3 は lib2to3 ライブラリを使って実装されています。
lib2to3 を使って変換ツールを自作する事も可能ですが、ドキュメント上には「 lib2to3 API は安定しておらず、将来、劇的に変更されるかも知れないと考えるべきです。」と言う注釈が付けられているので要注意です。
参考: http://docs.python.jp/3.4/library/2to3.html

2to3 は変換パターンに対応した変換名を指定する事で、特定の変換のみを行う事ができます。
“2to3 -l” 変換プログラムの一覧表示

 

  • “2to3 -f fix1 -f fix2 script-name” 特定の変換を適用
  • “2to3 -x fix1 -x fix2 script-name” 特定の変換を適用外

sixer

six で変換できる箇所のみを修正するツールで、Python 3 上でのみ動作します。OpenStack 向けに、OpenStack の開発メンバーが作成したものです。参考: https://pypi.python.org/pypi/sixer

context_unnester

contextlib.nested の変換のみに特化したツールで、これも OpenStack 向けに、 OpenStack の開発メンバーが作成したものです。参考: https://github.com/adrienverge/context_unnester

python-modernize

lib2to3 を利用して、2to3 相当の変換と six を使用した変換機能をサポートします。2to3 と同様に変換パターンを指定することができます。また ‘—no-six’ を指定すると six を使った変換は行われません。
参考: http://python-modernize.readthedocs.org/en/latest/

2to6

python-modernize とほぼ同じ機能を提供します。ただ、2013年7月28日のコミット以来更新がなく、pypi には未登録です。参考: https://github.com/limodou/2to6

python-future

python-modernize と同様に lib2to3 を利用して、2to3 相当の変換と six 機能を使用した変換を行います。また、それに加え独自のライブラリが実装されおり、以下の変換が行えます。

 

  • Python 2   →   Python 2/3
  • Python 3   →   Python 2/3

2to3 と同様に変換パターンを指定することもできます。変換によっては python-future のライブラリに依存したコードが挿入される事もあります。そのため、変換後のソースファイルは python-future なしでは動作しない可能性があり、その点が少し難点です。参考: http://python-future.org/

まとめ

単純に Python 3 用に変換する場合は 2to3 で変換後、足りない部分を修正します。Python 2 および Python 3 双方で動作させたい場合は、six を使用することになります。修正後は当然 six モジュールのインストールが必須となりますのでお忘れなく。

ツールとしては python-modernaize が全体的に機能を網羅しており、ツール依存の部分もないため (six が使われた場合はやはり six のインストールが必要となります) 無難と思われますが、2to3 や python-future に比べると変換し足りない部分があります。2to3 適用後 sixer や python-modernaize で six 部分の変換を行うなど組み合わせて使うと良いでしょう。

また大体のツールは変換の際、変換部分の修正イメージを表示してくれるので、最初は上書き指定をせずに動かしてみて、ツール毎にどんな変換がされるか予め確認して比較する事もできます。

いずれにしても変換して終了ではなく、変換後のソースコードはチェックして、足りない変換の追加、必要のない変換の戻し作業 (効率の悪いコードになっている場合があります)、および変換後のコードの動作確認は必要となります。あくまでも作業効率を上げるための補助ツールと考えるべきです。