2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Python2to3アップデート方法】futurizeで安全にPython2系コードを3系用に自動変換

Posted at

目次

コードを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

関連記事

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?