Python3も3.3になり性能も向上して、移行が順調に進んできているように見える。それを考慮して最近Python3系と2系の互換性確保を見直した。
ひとことでいうと「Python3中心」にした。
今までの手法
基本的に3系と2系の互換性確保は「単一ソースコード」でやっていてそれは今も変わらず。
で、今までは Python3とPython2の中間 のコードを書いていた。組み込みの関数のリネームなどはしない、というような(例えば zip
を izip
で上書いてしまうとか)。ただこの手法だといざPython2系のサポートをdropする場合に処理的にもコード的にも無駄が多くなる。
今の手法
rays の compat.py では以下のような方針とした。
- Python3中心。
- Python3の時に効率的に動作する
- Python2のサポートドロップ時にソース修正が容易
なのでガンガンPython2の関数はPython3に置き換える。( map
を imap
にしてしまうなど ) 大まかには compat.py のコメント通り以下のようなコーディング。
-
文字列は
str
とbytes
を使う。 -
range
,map
,zip
などはイテレータを返すものとする。 -
コレクションの列挙は
iter_items
などの関数を通す。 -
iterator.next()
の代わりにnext
関数を使う。 -
クラスは
object
の代わりにcompatobject
を継承する。__str__
,__nonzero__
,__cmp__
など廃止・仕様変更されたメソッドは Python3の仕様で実装する。compatobject
が Python2の場合は自動で変換する。
-
リネームされたモジュールのimportは
compat_import
メソッドを使う。- 例:
compat_import(py2="email.MIMEMultipart", py3="email.mime.multipart")
- このようにするとPython2でも
email.mime.multipart
でアクセスできる。
- このようにするとPython2でも
- 例:
-
urllib
は複雑にリネームされているので、 python2用urllib
を作ってしまう。- Python2でも普通に
import urllib.request
のように書ける
- Python2でも普通に
キモは compat_import
かなと。
そうすると、以下のような感じでほぼPython3のみ対象としたのと同じソースコードになる。Python2サポートdrop時は単純なソースコード置換でいけるはず。
1import urllib.request
2compat_import(py2="cookielib", py3="http.cookiejar")
3
4class Html(compatobject):
5 def __init__(self, text):
6 if isinstance(text, bytes):
7 text = text.decode("utf8")
8 self.text = text
9
10 def __str__(self):
11 return self.text
12
13cookie_jar = http.cookiejar.MozillaCookieJar()
14handlers = [urllib.request.HTTPCookieProcessor(cookie_jar)]
15opener = urllib.request.build_opener(*handlers)
16html = Html(opener.open("http://www.google.co.jp/").read())
ソースコードの寿命をのばすためにもボチボチこの方針で書き変えていくつもり。