目次
コードをPython 2系から3系用に自動変換する
Python2系のコードを3系用に自動変換してくれるツールであるfuturizeの使い方について説明する。
この記事を読む前に
コード変換ツールはいくつかあり、それぞれ特徴が異なる。
まずは自分の環境にどのツールが合うのか、以下の記事を読んで判断することをオススメする。
stageについて
futurizeを理解するためには、stageについて理解しておく必要がある。
futurizeのコード変換方式には、stage1と2がある。
stage1
stage1は、Python2系環境でも影響のない範囲でのコード変換を行う。そのため、stage1での変換後コードは、Python3系環境では動かない可能性がある。stage1の目的は、Python3系用にコードを完全に変化する前段階として、まずはPython2で動く範囲でのコード変換を行うことである。stage1を挟むことにより、一気にコードを変換するリスクを和らげることができる。
stage1では、__future__モジュールを利用し、Python3系にあって2系では互換性がない機能でも、2系の環境で実装できるようにする。futureモジュールは追加しない。
stage2
stage2では、Python3系用に完全にコードを書き換える。ただし、Python2系でも動く内容で安全に変換を行うため、[2to3を使った場合とは実装内容が異なる](【Python2to3アップデート方法】2to3 vs futurize どちらでソースコード変換をすればよいのか)。stage2では、futureモジュールを追加する。
事前準備
まずは検証用に、2系では動くが3系では動かないソースコードを作成する。
以下の記事の「事前準備」の項を参考して作成してください。
futurizeでコードを変換
Installation
futurizeコマンドを利用するには、pipモジュールのインストールが必要。
$ pip install future
Usage
stage1
まずは、stage1でコードの変更が必要な箇所をチェックする。
この段階ではまだdry-runであり、コードの変換は行われない。
$ futurize --stage1 project
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: ws_comma
RefactoringTool: Refactored project/base.py
--- project/base.py (original)
+++ project/base.py (refactored)
@@ -1,4 +1,5 @@
# -*- coding:utf-8 -*-
+from __future__ import print_function
import libs.sample_class as sc
@@ -6,5 +7,5 @@
'''
It should be `print()` with Python3.x
'''
- print 'This is a sample.\n'
+ print('This is a sample.\n')
sc.SampleClass().sample_method()
RefactoringTool: No changes to project/libs/base.py
RefactoringTool: Refactored project/libs/sample_class.py
--- project/libs/sample_class.py (original)
+++ project/libs/sample_class.py (refactored)
@@ -4,7 +4,9 @@
- `import PRJ_ROOT/base.py` with Python2.x
- `import PRJ_ROOT/libs/base.py` with Python3.x
'''
-import base
+from __future__ import print_function
+from __future__ import absolute_import
+from . import base
'''
It should be `configparser` with Python3.x
'''
@@ -17,11 +19,11 @@
'''
It should be `print()` with Python3.x
'''
- print '[division]'
+ print('[division]')
'''
# Results
- `0` with Python 2.x
- `0.5` with Python 3.x
'''
- print '1/2 = {}'.format(1/2)
- print '1//2 = {}'.format(1//2)
+ print('1/2 = {}'.format(1/2))
+ print('1//2 = {}'.format(1//2))
RefactoringTool: Files that need to be modified:
RefactoringTool: project/base.py
RefactoringTool: project/libs/base.py
RefactoringTool: project/libs/sample_class.py
コード自動変換
以下のコマンドで、実際にコードを書き換える。
-w
オプションを付けることで、ファイルを上書きして書き換えてくれる。
実行すると、バックアップファイルも作成される。
$ futurize --stage1 -w project
--nobackups
オプションを付けると、バックアップファイルは作成されない。
$ futurize --stage1 -w --nobackups project
stage2
stage1での変換後に実施する。
次に、stage2でコードの変更が必要な箇所をチェックする。
この段階ではまだdry-runであり、コードの変換は行われない。
$ futurize --stage2 project
RefactoringTool: Refactored project/libs/base.py
--- project/libs/base.py (original)
+++ project/libs/base.py (refactored)
@@ -1,11 +1,12 @@
# -*- coding:utf-8 -*-
+from builtins import object
from abc import ABCMeta, abstractmethod
+from future.utils import with_metaclass
-class Base(object):
+class Base(with_metaclass(ABCMeta, object)):
'''
The way of using Abstract differs between Python 2.x and 3.x
'''
- __metaclass__ = ABCMeta
@abstractmethod
def sample_method(self):
RefactoringTool: Refactored project/libs/sample_class.py
--- project/libs/sample_class.py (original)
+++ project/libs/sample_class.py (refactored)
@@ -6,11 +6,15 @@
'''
from __future__ import print_function
from __future__ import absolute_import
+from __future__ import division
+from future import standard_library
+standard_library.install_aliases()
+from past.utils import old_div
from . import base
'''
It should be `configparser` with Python3.x
'''
-import ConfigParser
+import configparser
class SampleClass(base.Base):
@@ -25,5 +29,5 @@
- `0` with Python 2.x
- `0.5` with Python 3.x
'''
- print('1/2 = {}'.format(1/2))
+ print('1/2 = {}'.format(old_div(1,2)))
print('1//2 = {}'.format(1//2))
RefactoringTool: Files that need to be modified:
RefactoringTool: project/libs/base.py
RefactoringTool: project/libs/sample_class.py
コードを自動変換
以下のコマンドで、実際にコードを書き換える。
-w
オプションを付けることで、ファイルを上書きして書き換えてくれる。
実行すると、バックアップファイルも作成される。
$ futurize --stage2 -w project
--nobackups
オプションを付けると、バックアップファイルは作成されない。
$ futurize --stage2 -w --nobackups project
コード自動変換後の3系での実行結果
書き換えを行ったコードを3系で実行してみる。
$ python base.py
This is a sample.
[division]
1/2 = 0
1//2 = 0