標準ライブラリに学ぶ Python 3.0移行のポイント
2009/03/11 19:30から行われたPython Code Reading 08 お題
標準ライブラリに学ぶ Python 3.0 移行のポイント
by ふるかわとおる氏
内容的には、Python 3 に移行した際に、発生するであろうトラブルや、どのように移行すべきか、問題を直すべきか、といったものです。
個人的にとてもとてもニーズのある話題で、ブラボーブラボーな感じです。
Python Code Readingに参加するような層のメンバーには、必要になることも多いでしょう。
動かなくなったコードを修正するには
print文
2.Xの場合
print ... print ..., print ... print >>stream, ...
3.0 では、printが関数になりました。
ちょっとしたコードを書くときは、今までより、面倒なことになりそうです。
print(...) # print関数で、出力後、改行したくない時はendを指定する。 print(..., end='')
2.Xの次のコードは、
print "spam",
3.0ではこう書きます。
print ("spam", end='')
文字列
- unicodeがベースに
- bytes型が追加された
- u"..."が廃止。
- b"..."が追加。
base64.pyモジュールの
def encodestring(s):
に、従来どおりstringを渡すと、TypeErrorを投げてしまう、という報告がありました。
同関数は、3.0でbytes型を受けるよう変更された。
このモジュールと似たような修正が入るモジュールは多いでしょう。
3.0に移行すると、あちこちでTypeErrorが投げられることになりそう。
ファイル
2.Xの場合
return open(filename).read(),
3.0では、デコードした文字列が返るように。エンコードはファイルを開く時に指定。本来あるべき形でしょう。
今までのコードを置き換える場合、一番面倒そうなのが、このファイルの部分だと思います。
エンコード指定箇所と、ファイルを開く場所が離れていると、面倒なことになるだろう。
return open(filename, encoding=encoding).read(),
バイナリの書き込みはbytes型を使用する。
3.0では、ファイル読み込み時点でエンコーディングを指定します。
文字化けなどの理由で、bytes型でファイルを開かねばならない時もあるかもしれない。
例外のキャッチ
2.Xでの例外のキャッチ
try: pwd = os.getcwd() # catchしたos.errorがmsgに入る except os.error, msg: print "os.error"
2.X。複数の例外をキャッチする場合
try: pwd = os.getcwd() except (ValueError, IndexError), var: print "os.error"
一方、3.0の例外の指定方法。
気のせい程度ですが、こちらの方が分かりやすいですね。
try: pwd = os.getcwd() except os.error as msg: print "os.error"
例外のスロー
2.Xの場合
# クラスAttributeError 変数varに入れて投げる raise AttributeError, var
3.0の場合
こちらの方が、言語仕様知らない人でも、わかりやすい。
raise AttributeError(var)
文字列例外の廃止
文字列例外がなくなった。
置き換える時はどうする? 例外クラスを定義するべきか、他の例外で指定すべきか。
例外は全体に分かりやすくなったように思います。
raise "MyException"
イテレータ
2.Xの場合
iter.next()
3.0の場合
next(iter)
3.0の方がわかりにくいような? そんな大差ある訳じゃないですけど。
3.0に移行するなら、割と修正が発生しそうな内容です。
辞書
keys() items(), values()がリストを返すのではなく、ビューを返すようになった。
ビューは、元のリストを返ると、表示される内容も変わってしまうもの。
2.Xの場合
# リストを返す environ.keys()
3.0の場合
# ビューを返す # 見た目は変わらない environ.keys() # しかし、データの変更にあわせて、ビューも変更される view = environ.keys() environ["xxx"] = .... print(environ)
この変更はトラブルを多数発生させそう。
防御的コピーを使って、データが変更されないように保護すべき場面もありそうだ。
他、いろいろ
廃止 __comp__() 。代わりに __lt__() を使用すれば良い。
ただし、pythonでは、-1もtrueになるので、単純に置き換えるのはアブない。
廃止 __getitem__() 。代わりに __getslice__()
廃止 file() 。代わりに open()
廃止 <> 。代わりに !=
廃止 __nonzero__ 。代わりに __bool__
たくさんあるが、詳しくは、What's New in Python 3.0に書いてある。
変換ツール 2to3 コマンド
# diffを出力 2to3 test.py # ファイルに出力 2to3 -w out.txt test.py
できること
- モジュールの位置移動に対応している
- print文の置き換え
- イテレータの置き換え
できないこと
- __cmp__メソッドしかない場合、__lt__メソッドを追加してはくれない。
- sliceの変換に失敗
- ファイルを開くところ。開く時点でエンコード指定が必要。
- reduce() は変換しない
3.0に移行すべきか
ほとんどは局所的に修正すれば大丈夫。
文字列はファイルなどの境界での修正で対応。
感想
今回の内容はとても良かった。
事前に配られた資料がかなりのボリュームで、これだけでも読む価値ありました。