.. _chap2to3:
==========================================
\ :py:mod:`2to3`\ ツールの使い方
==========================================
:py:mod:`2to3`\ の概要
+++++++++++++++++++++++++++++++++++++++++++++++++
.. |2to3| replace:: :py:mod:`2to3`
.. |fixer| replace:: https://docs.python.org/ja/3/library/2to3.html#fixers
|2to3| はPythonと共にインストールされる **標準的なツール** で、
その名の通りPython2向けのソースコードを、Python3対応のソースコードに
変換してくれます。後に説明する :py:mod:`future` モジュールも類似の機能を持つています(:any:`future_module` 参照)。
\ |2to3|\ はpython2対応コードをpython3対応コードに
変換する際に必要な変更のほとんどに対応していますが、若干の手直しを
必要とする場合があります。
しかしながら、Python2向けソースコードを
Python3対応にする為の最初の一歩としては必須のツールです。
:py:mod:`future` モジュールの futureize コマンドや Modernize コマンドも内部ではlib2to3の機能を使っています。
.. hint:: 参考URL
:name: future モジュールについてのドキュメント(URL)
`python-modernize `_
`Automatic conversion to Py2/3 `_
`How to port Python 2 Code to Python 3 `_
:py:mod:`2to3`\ の基本的な使い方
+++++++++++++++++++++++++++++++++++++++++++++++++
|2to3|\ が変更された文法のどれに対応しているかは、
.. code-block:: bash
2to3 -l
を実行することで確認できます。
この文章作成時に実行したところ、52の変換項目(変換サブプログラムに対応している)が挙げられました。 [#]_
.. [#] 2to3-3.10でもこの数(52)は同じでした。
.. hlist::
:columns: 5
* apply
* asserts
* basestring
* *buffer*
* dict
* except
* exec
* execfile
* exitfunc
* filter
* funcattrs
* future
* getcwdu
* has_key
* *idioms*
* import
* imports
* imports2
* input
* intern
* isinstance
* itertools
* itertools_imports
* long
* map
* metaclass
* methodattrs
* ne
* next
* nonzero
* numliterals
* operator
* paren
* print
* raise
* raw_input
* reduce
* reload
* renames
* repr
* *set_literal*
* standarderror
* sys_exc
* throw
* tuple_params
* types
* unicode
* urllib
* *ws_comma*
* xrange
* xreadlines
* zip
これらの変換項目は "``-f``"オプションや"``-x``"オプションを追加することで、明示的に変換項目に有効化/無効化を指定できます。
これらの変換項目のいくつか( *buffer*, *idioms*, *set_lieteral*, *ws_comma* )はオプショナルな変換項目となっており、通常は無効化されています。
これらの変換項目による結果は、厳密に等価なプログラムを与える訳では無いことから、オプショナルな変換項目となっているようです。
\ ``-f``\ を使って変換項目を指定すると、明示的に指定した変換項目だけが有効化されます。既定の変換項目に変換項目を追加するには、
.. code-block:: bash
2to3 -f all -f <変換項目名> .
とします。
変換項目(変換プログラム)
-------------------------
上にあげた変換項目(apply,...) の内容は、例えば
\ https://docs.python.org/ja/3/library/2to3.html#fixers\
に説明されています。
これらの変換プログラムのうち、
``imports/imports2`` は ``python2`` から ``python3`` への移行時にモジュール名が変更されたモジュール(例えばTkinter -> tkinter)に対応してくれます。
importsでは、Tkinter, FileDialo, Tix, ttk などのTk関係のモジュール、dbmに関連したモジュール, xmlrpcサーバ関係のモジュール、
httplibやHTTPServerに関連したモジュールなどに対応しています。
また、imports2ではwhichdbm, anydbmの使用がdbmモジュールを使うように変更されます。
importsとimports2に分離されているのは、"単に技術的な制約のため" だそうです。
``urllib`` については ``imports`` とは別に変換プログラム ``urllib``(fix_urllib.py)が用意されています。
``idioms`` 変換プログラムは、"Python コードをより Python らしい書き方" にするいくつかの変形を行います。
objectの型\ :code:`type(obj)`\ とTypeオブジェクト\ :code:`T`\ との
比較を、可能なところでは、\ :code:`isInstance(obj,T)`\ に置き換える、
\ :code:`while 1:`\ を\ :code:`while True:`\ に置き換える、
可能な場所では\ :code:`sorted(EXPR)`\ を使う、等の変換を行います。
Tabとスペース
------------------
http://python3porting.com/differences.html#index-14 には次の記載があります。
In Python 2 a tab will be equal to eight spaces as indentation, so you can indent one line with a tab, and the next line with eight spaces. This is confusing if you are using an editor that expands tabs to another number than eight spaces.
In Python 3 a tab is only equal to another tab. This means that each indentation level has to be consistent in its use of tabs and spaces. If you have a file where an indented block sometimes uses spaces and sometimes tabs, you will get the error TabError: inconsistent use of tabs and spaces in indentation.
つまり、python2では 一つのブロック中で tabとspaceを混在しても、tabとspaceの関係( 1 tab = 8 spaces)を使ってブロック内
の各行の始まりが一致していれば問題はありませんでした。
一方python3 では、同じブロックの中では、tabとスペースの数と位置が一致している必要があります。
このため、同じブロック内でtabとスペースの数が異なる行があるスクリプトでは、python2では動作するけれど、python3では動作しないことになります。
TABと空白の混在はエディタなどの環境の違いによって、見かけ上の構造と
Pythonインタプリタからみた構造が異なる場合があります。
これはpython2においても同様ですので、python2/python3にかかわらずTABと空白の混在は避けておくのが得策です。
ちなみに私自身はemacsのPython-modeを使いpythonプログラムを開発します。
此の環境では、キーボードからのTAB入力は複数の空白に置き換えてくれます。
デフォルトは4個の空白ですが、これを変更することも可能です(Preference
で\ ``Python Indent Offset``\ を変更する)。
変更部分の確認
---------------------
|2to3|\ を出力を指定するオプションをつけずに実行することで、
|2to3|\ が加える変更をdiff形式の出力で確認できます。
.. code-block:: bash
2to3 *.py
あるいは
.. code-block:: bash
2to3 .
で現在にディレクトリにあるpythonコードで必要な変換内容を確認します。
必要に応じて、``-f``あるいは``-x``オプションをつけて変更項目の有効化/無効化を試行して見ます。
新しいディレクトリにPytho3対応ソースコードを作成する。
----------------------------------------------------------------------------------------------------
|2to3|\ には様々なオプションが用意されていますが、次のシェルコマンド
.. code-block:: bash
mkdir ../PY3
2to3 -W -n -o ../PY3 .
を知っていれば、最低限の用は足りるでしょう。このコマンドは、
python2のソースコードのディレクトリに現在居るとして、
#. Python3用の作業ディレクトリ../PY3を作成し、(mkdir ../PY3)
#. そのディレクトリに現在のディレクトリにある全てのPythonソースコードを\ |2to3|\ で必要な場合には、Python3向けに変換し、(|2to3|\ )
#. 変換の必要の無いファイルを含めて(-W -n)
#. 新しいディレクトリ(../PY3)に書き出します。(-o ../PY3)
#. ``-n`` オプションは、オリジナルのPython2向けコードをbackupとして作成しないことを指定しています。
``-n`` オプションは ``-o`` オプション を使う際には必須となっています。
\ |2to3|\ コマンドの詳細は、
.. code-block:: bash
2to3 --help
で確認できます。
mercurialなどを使って管理している場合
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ソースコードを mercurial などの管理ツールを使って
管理している場合には、ブランチなどの機能を使って、python3版の
開発を進めることが考えられます。
.. code-block:: bash
mkdir PY3
cd PY3
hg clone .
によって、現在のバージョンのコピーを作業ディレクトリ(PY3)に作成します。ここで、
.. code-block:: bash
2to3 -w -n .
を実行すると、Python3への変更が必要なファイルだけが\ |2to3|\ によって変更されます。
変更前のファイルをバックアップとして残して置きたい場合には、
.. code-block:: bash
2to3 -w
とします。もっとも、hgで管理しているのであれば、hg diffで見ることができるので、あまり必要な無いように思われます。
setup ツールとの連携
-------------------------
setuptoolsを使ったinstall scriptでは、``use_2to3`` オプション
を設定することで、”setup.py intall"実行時に自動的に\ |2to3|\ を適用してからインストールすることができます。
後で見るように、|2to3|\ で自動変換したプログラムがpython3では意図した動作とならない場合があることから、その有用性はあまり無いのかもしれません。 setuptools のドキュメントでも
.. epigraph::
Setuptools provides a facility to invoke 2to3 on the code as a part of the build process, by setting the keyword parameter use_2to3 to True, but the Setuptools project strongly recommends instead developing a unified codebase using six, future, or another compatibility library.
-- setuptools 45.2.0 documentation
となっています。一般的には、この記述にも触れられている :py:mod:`six` あるいは :py:mod:`future` などのモジュールを使うことが推奨されています。必要な変更の数が少ない場合には、有効な方法ですので、ダメもとで一度試して見るだけの価値は有りそうです。