第 4 回 移植に使えるユーティリティ その2
今回は、「第 3 回 移植に使えるユーティリティ その1」で紹介した移植ユーティリティについての変換例を紹介します。
削除されたメソッドのケース (python-modernize 使用の場合)
$ cat samp_remove.py
import itertools
d1 = {'a': '1', 'b': '2'}
b = b'abcd'
u = unicode(b)
if u == b:
print "equal binary u=%s" % u
else:
print "not binary u=%s" % u
for k, v in d1.iteritems():
print "iteritems() k=%s v=%s" % (k, v)
ivals = d1.itervalues()
while True:
n = ivals.next()
print "iterator.next() n=%s" % n
if n == '2':
break
for i in xrange(2):
print "xrange() i=%d" % i
it = itertools.imap(str, [1, 2])
for s in it:
print "itertools.imap() s=%s" % s
a = 1
b = 2
if cmp(a, b) < 0:
print "a < b"
$ python-modernize -w samp_remove.py
root: Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
…
RefactoringTool: Refactored samp_remove.py
--- samp_remove.py (original)
+++ samp_remove.py (refactored)
@@ -1,32 +1,36 @@
+from __future__ import absolute_import
+from __future__ import print_function -- 1)
import itertools
+import six
+from six.moves import range
d1 = {'a': '1', 'b': '2'}
b = b'abcd'
-u = unicode(b)
+u = six.text_type(b) -- 2)
if u == b:
- print "equal binary u=%s" % u
+ print("equal binary u=%s" % u) -- 3)
else:
- print "not binary u=%s" % u
+ print("not binary u=%s" % u)
-for k, v in d1.iteritems():
- print "iteritems() k=%s v=%s" % (k, v)
+for k, v in six.iteritems(d1): -- 4)
+ print("iteritems() k=%s v=%s" % (k, v))
-ivals = d1.itervalues()
+ivals = six.itervalues(d1)
while True:
- n = ivals.next()
- print "iterator.next() n=%s" % n
+ n = next(ivals)
+ print("iterator.next() n=%s" % n)
if n == '2':
break
-for i in xrange(2):
- print "xrange() i=%d" % i
+for i in range(2):
+ print("xrange() i=%d" % i)
it = itertools.imap(str, [1, 2]) -- 5)
for s in it:
- print "itertools.imap() s=%s" % s
+ print("itertools.imap() s=%s" % s)
a = 1
b = 2
if cmp(a, b) < 0: -- 5)
- print "a < b"
+ print("a < b")
RefactoringTool: Files that were modified:
RefactoringTool: samp_remove.py
$
編集
$ diff -u samp_remove.py.bak samp_remove.py
--- samp_remove.py.bak 2015-09-03 06:29:19.142521670 +0000
+++ samp_remove.py 2015-09-03 06:29:51.166738014 +0000
@@ -26,11 +26,11 @@
for i in range(2):
print("xrange() i=%d" % i)
-it = itertools.imap(str, [1, 2]) -- 6)
+it = map(str, [1, 2])
for s in it:
print("itertools.imap() s=%s" % s)
a = 1
b = 2
-if cmp(a, b) < 0: -- 6)
+if a < b:
print("a < b")
$
- Python 2 で print() 関数をサポートするために future 文を追加
- Python 2 では unicode()、Python 3 では str() に展開
- print 文 を print 関数に変換
- Python 2 では iter(dict.iteritems())、Python 3 では iter(dict.items()) に展開
dict_items オブジェクトはイテレータとは属性が異なるためイテレータに変換 - 変換が必要だが未変換
- 変換が必要だがユーティリティでは対象外になっているため、手動で変更
【実行結果】
Python 2 と Python3 で動作確認
変換前
$ python2 samp_remove.py
equal binary u=abcd
iteritems() k=a v=1
iteritems() k=b v=2
iterator.next() n=1
iterator.next() n=2
xrange() i=0
xrange() i=1
itertools.imap() s=1
itertools.imap() s=2
a < b
$ python3 samp_remove.py
File "samp_remove.py", line 6
print "equal binary u=%s" % u
^
SyntaxError: invalid syntax
$
変換後
$ python2 samp_remove.py
equal binary u=abcd
iteritems() k=a v=1
iteritems() k=b v=2
iterator.next() n=1
iterator.next() n=2
xrange() i=0
xrange() i=1
itertools.imap() s=1
itertools.imap() s=2
a < b
$ python3 samp_remove.py
not binary u=b'abcd'
iteritems() k=a v=1
iteritems() k=b v=2
iterator.next() n=1
iterator.next() n=2
xrange() i=0
xrange() i=1
itertools.imap() s=1
itertools.imap() s=2
a < b
$
削除されたメソッドのケース (2to3 使用の場合)
$ 2to3 -w samp_remove.py
root: Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
…
RefactoringTool: Refactored samp_remove.py
--- samp_remove.py (original)
+++ samp_remove.py (refactored)
@@ -3,30 +3,30 @@
d1 = {'a': '1', 'b': '2'}
b = b'abcd'
-u = unicode(b)
+u = str(b) -- 1)
if u == b:
- print "equal binary u=%s" % u
+ print("equal binary u=%s" % u)
else:
- print "not binary u=%s" % u
+ print("not binary u=%s" % u)
-for k, v in d1.iteritems():
- print "iteritems() k=%s v=%s" % (k, v)
+for k, v in d1.items(): -- 2)
+ print("iteritems() k=%s v=%s" % (k, v))
-ivals = d1.itervalues() -- 3)
+ivals = iter(d1.values())
while True:
- n = ivals.next()
- print "iterator.next() n=%s" % n
+ n = next(ivals)
+ print("iterator.next() n=%s" % n)
if n == '2':
break
-for i in xrange(2):
- print "xrange() i=%d" % i
+for i in range(2):
+ print("xrange() i=%d" % i)
-it = itertools.imap(str, [1, 2])
+it = map(str, [1, 2]) -- 4)
for s in it:
- print "itertools.imap() s=%s" % s
+ print("itertools.imap() s=%s" % s)
a = 1
b = 2
if cmp(a, b) < 0:
- print "a < b"
+ print("a < b")
$
- str() に変換
- dict.items() に変換
- iter(d1.values()) に変換
- map() に変換 (python-modernize() では変換されていなかった)
戻り値がリストからイテレータに変わったケース
$ cat samp_iterator.py
d1 = {'a': '1', 'b': '2', 'c': '3'}
for k, v in d1.items():
print "items() k=%s" % k
s = map(str, [1, 2, 3])
print "map=%s" % s
s = map(str, [1, 2, 3])[1]
print "map=%s" % s
$ python-modernize -w samp_iterator.py
root: Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
…
RefactoringTool: Refactored samp_iterator.py
--- samp_iterator.py (original)
+++ samp_iterator.py (refactored)
@@ -1,9 +1,12 @@
+from __future__ import absolute_import
+from __future__ import print_function
+from six.moves import map
d1 = {'a': '1', 'b': '2', 'c': '3'}
-for k, v in d1.items():
- print "items() k=%s" % k
+for k, v in list(d1.items()):
+ print("items() k=%s" % k)
-s = map(str, [1, 2, 3])
-print "map=%s" % s
+s = list(map(str, [1, 2, 3]))
+print("map=%s" % s)
s = map(str, [1, 2, 3])[1]
-print "map=%s" % s
+print("map=%s" % s)
RefactoringTool: Files that were modified:
RefactoringTool: samp_iterator.py
$
編集
$ diff -u samp_iterator.py.bak samp_iterator.py
--- samp_iterator.py.bak 2015-09-02 10:36:48.880141958 +0000
+++ samp_iterator.py 2015-09-02 10:43:56.027294096 +0000
@@ -1,9 +1,12 @@
+from __future__ import absolute_import
+from __future__ import print_function
+from six.moves import map
d1 = {'a': '1', 'b': '2', 'c': '3'}
-for k, v in d1.items():
- print "items() k=%s" % k
+for k, v in list(d1.items()): -- 1)
+ print("items() k=%s" % k)
-s = map(str, [1, 2, 3])
-print "map=%s" % s
+s = list(map(str, [1, 2, 3]))
+print("map=%s" % s)
-s = map(str, [1, 2, 3])[1]
-print "map=%s" % s
+s = list(map(str, [1, 2, 3]))[1]
+print("map=%s" % s)
$ python2 samp_iterator.py
items() k=a
items() k=c
items() k=b
map=['1', '2', '3']
map=2
$ python3 samp_iterator.py
items() k=b
items() k=c
items() k=a
map=['1', '2', '3']
map=2
$
- ここではイテレータのままでも問題ないが、ユーティリティが無条件に list() を使用する様に変換している。
str 型と bytes 型
$ cat samp_str.py
import struct
p = struct.pack('2sisi', 'aa', 3, 'b', 100)
print "struct.pack()=", struct.unpack('2sisi', p)
s = b'abcde'
b_cmp = 'c'
if s[2] == b_cmp:
print "s[2] equal %s:" % b_cmp, s[2]
else:
print "s[2] not equal %s:" % b_cmp, s[2]
$ python-modernize -w samp_str.py
…
$
編集
$ diff -u samp_str.py.bak samp_str.py
--- samp_str.py.bak 2015-09-03 23:48:54.612342691 +0000
+++ samp_str.py 2015-09-03 23:51:39.613462446 +0000
@@ -1,11 +1,13 @@
+from __future__ import absolute_import
+from __future__ import print_function
import struct
-p = struct.pack('2sisi', 'aa', 3, 'b', 100)
-print "struct.pack()=", struct.unpack('2sisi', p)
+p = struct.pack('2sisi', b'aa', 3, b'b', 100) -- 1)
+print("struct.pack()=", struct.unpack('2sisi', p))
s = b'abcde'
-b_cmp = 'c'
+b_cmp = 99 - - 2)
if s[2] == b_cmp:
- print "s[2] equal %s:" % b_cmp, s[2]
+ print("s[2] equal %s:" % b_cmp, s[2])
else:
- print "s[2] not equal %s:" % b_cmp, s[2]
+ print("s[2] not equal %s:" % b_cmp, s[2])
$ python2 samp_str.py
struct.pack()= ('aa', 3, 'b', 100)
s[2] not equal 99: c
$ python3 samp_str.py
struct.pack()= (b'aa', 3, b'b', 100)
s[2] equal 99: 99
$
- 書式 s の引数を bytes 型に変更
- Python 3 では bytes のインデックスでの参照は数字になるため変更
編集
$ diff -u samp_str.py.bak samp_str.py
--- samp_str.py.bak3 2015-09-03 23:51:39.613462446 +0000
+++ samp_str.py 2015-09-03 23:53:17.390125938 +0000
@@ -1,12 +1,16 @@
from __future__ import absolute_import
from __future__ import print_function
+import six
import struct
p = struct.pack('2sisi', b'aa', 3, b'b', 100)
print("struct.pack()=", struct.unpack('2sisi', p))
s = b'abcde'
-b_cmp = 99
+if six.PY3:
+ b_cmp = 99
+else:
+ b_cmp = 'c'
if s[2] == b_cmp:
print("s[2] equal %s:" % b_cmp, s[2])
else:
$ python2 samp_str.py
struct.pack()= ('aa', 3, 'b', 100)
s[2] equal c: c
$ python3 samp_str.py
struct.pack()= (b'aa', 3, b'b', 100)
s[2] equal 99: 99
$
contextlib.nested
$ cat samp_nested.py
import contextlib
import mock
with contextlib.nested(
mock.patch.object(self.ovs, 'set_protocols'),
mock.patch.object(self.ovs, 'set_controller'),
) as (mock_set_protocols, mock_set_controller):
self.assertEqual(mock_set_protocols.call_count, 1)
self.assertEqual(mock_set_controller.call_count, 1)
$ cp -p samp_nested.py samp_nested.py.orig
$ context_unnester/context_unnester.py samp_nested.py
samp_nested.py
$ context_unnester.py samp_nested.py
samp_nested.py
$ cat samp_nested.py
import mock
with mock.patch.object(self.ovs, 'set_protocols') as mock_set_protocols,
mock.patch.object(self.ovs, 'set_controller') as mock_set_controller:
self.assertEqual(mock_set_protocols.call_count, 1)
self.assertEqual(mock_set_controller.call_count, 1)
$
$ cat samp_misc.py
import sys
i = 5 / 2
print >> sys.stderr, "i=",
print >> sys.stderr, i
i = 5 // 2
print >> sys.stderr, "i=", i
try:
raise IOError, 'some errors occured'
except IOError, ex:
print "ex=%s" % ex.message
$ python-modernize -w samp_misc.py
root: Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
…
$
編集
$ diff -u samp_misc.py.bak samp_misc.py
--- samp_misc.py.bak 2015-09-02 04:25:08.438598822 +0000
+++ samp_misc.py 2015-09-02 04:27:31.175616793 +0000
@@ -1,11 +1,13 @@
+from __future__ import absolute_import
+from __future__ import print_function
import sys
i = 5 / 2
-print >> sys.stderr, "i=",
-print >> sys.stderr, i - 1)
+print("i=", end=' ', file=sys.stderr)
+print(i, file=sys.stderr)
i = 5 // 2
-print >> sys.stderr, "i=", i
+print("i=", i, file=sys.stderr)
try:
- raise IOError, 'some errors occured'
-except IOError, ex: -- 2)
- print "ex=%s" % ex.message
+ raise IOError('some errors occured')
+except IOError as ex:
+ print("ex=%s" % ex.args[0])
$ python2 samp_misc.py
i= 2
i= 2
ex=some errors occurred
$ python3 samp_misc.py
i= 2.5 -- 3)
i= 2
ex=some errors occured
$
- 末尾の出力を end 引数に、出力先を file 引数に変換
- ex を as ex に。message 属性は削除されたので args に変換
- Python 3 では ‘/’ の結果は浮動小数点になる