目次
概要
Python2系のコードを3系用に自動変換してくれるツールであり、Pythonに標準で同梱されているモジュールである2to3の使い方について説明する。
ただし、このツールで変更が必要な箇所全てを網羅できるわけではないので注意してください。
この記事を読む前に
コード変換ツールはいくつかあり、それぞれ特徴が異なる。
まずは自分の環境にどのツールが合うのか、以下の記事を読んで判断することをオススメする。
事前準備
まずは検証用に、2系では動くが3系では動かないコードを作成する。
ディレクトリ構成
以下の構成で作成する。
.
`-- project
|-- base.py
`-- libs
|-- __init__.py
|-- base.py
`-- sample_class.py
検証用コード
以下のファイルを作成する。
# -*- coding:utf-8 -*-
import libs.sample_class as sc
if __name__ == '__main__':
'''
3系ではprint()にする必要がある
'''
print 'This is a sample.\n'
sc.SampleClass().sample_method()
# -*- coding:utf-8 -*-
'''
2系ではproject/libs/base.pyがimportされる
3系ではproject/base.pyがimportされる
'''
import base
'''
3系ではconfigparser
'''
import ConfigParser
class SampleClass(base.Base):
def sample_method(self):
'''
3系ではprint()にする必要がある
'''
print '[division]'
'''
# 計算結果
- 2系 => 0
- 3系 => 0.5
'''
print '1/2 = {}'.format(1/2)
print '1//2 = {}'.format(1//2)
# -*- coding:utf-8 -*-
from abc import ABCMeta, abstractmethod
class Base(object):
'''
3系ではAbstractの書き方が異なる
'''
__metaclass__ = ABCMeta
@abstractmethod
def sample_method(self):
raise NotImplementedError()
project/libs/__init__.py
空で作成する。
実行結果
2系での実行結果
以下が出力される。
$ python project/base.py
This is a sample.
[division]
1/2 = 0
1//2 = 0
3系での実行結果
3系と互換性がない書き方なので、当然エラーとなる。
$ python project/base.py
Traceback (most recent call last):
File "base.py", line 2, in <module>
import libs.sample_class as sc
File "/code/libs/sample_class.py", line 9
print '[division]'
^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print('[division]')?
2to3でコードを変換
Installation
2to3を利用するためには以下のインストールが必要。
# CentOSの場合
$ yum install python-tools
# Ubuntuの場合
$ apt-get install 2to3
Usage
変更が必要な箇所をチェック
projectディレクトリに対して、2to3を実行すると、再帰的にチェックしてくれる。
この段階ではまだdry-runであり、コードの変換は行われない。
$ 2to3 project/
RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
RefactoringTool: Refactored project/base.py
--- project/base.py (original)
+++ project/base.py (refactored)
@@ -6,5 +6,5 @@
'''
3系ではprint()にする必要がある
'''
- print 'This is a sample.\n'
+ print('This is a sample.\n')
sc.SampleClass().sample_method()
RefactoringTool: Refactored project/libs/base.py
--- project/libs/base.py (original)
+++ project/libs/base.py (refactored)
@@ -1,11 +1,10 @@
# -*- coding:utf-8 -*-
from abc import ABCMeta, abstractmethod
-class Base(object):
+class Base(object, metaclass=ABCMeta):
'''
3系ではAbstractの書き方が異なる
'''
- __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)
@@ -4,11 +4,11 @@
2系ではproject/libs/base.pyがimportされる
3系ではproject/base.pyがimportされる
'''
-import base
+from . import base
'''
3系ではconfigparser
'''
-import ConfigParser
+import configparser
class SampleClass(base.Base):
@@ -17,11 +17,11 @@
'''
3系ではprint()にする必要がある
'''
- print '[division]'
+ print('[division]')
'''
# 計算結果
- 2系 => 0
- 3系 => 0.5
'''
- 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
オプションを付けることで、ファイルを上書きして書き換えてくれる。
実行すると、バックアップファイルも作成される。
$ 2to3 -w project/
--nobackups
オプションを付けると、バックアップファイルは作成されない。
$ 2to3 -w --nobackups project/
コード自動変換後の3系での実行結果
書き換えを行ったコードを3系で実行してみる。
エラーは起きなくなった。また、1/2
の実行結果が0.5
になった。
参考:Python2系と3系の違い - 割り算の少数点以下の扱いについて
$ python project/base.py
This is a sample.
[division]
1/2 = 0.5
1//2 = 0
最後に
冒頭でも書きましたが、このツールで変更が必要な箇所全てを網羅できるわけではないので、動作確認をしながら修正必要箇所を見つけていく、という作業は必要になります。