Python3 & 2互換性確保の見直し

Python3も3.3になり性能も向上して、移行が順調に進んできているように見える。それを考慮して最近Python3系と2系の互換性確保を見直した。

ひとことでいうと「Python3中心」にした。

今までの手法

基本的に3系と2系の互換性確保は「単一ソースコード」でやっていてそれは今も変わらず。

で、今までは Python3とPython2の中間 のコードを書いていた。組み込みの関数のリネームなどはしない、というような(例えば zipizip で上書いてしまうとか)。ただこの手法だといざPython2系のサポートをdropする場合に処理的にもコード的にも無駄が多くなる。

今の手法

rayscompat.py では以下のような方針とした。

  • Python3中心。
    • Python3の時に効率的に動作する
    • Python2のサポートドロップ時にソース修正が容易

なのでガンガンPython2の関数はPython3に置き換える。( mapimap にしてしまうなど ) 大まかには compat.py のコメント通り以下のようなコーディング。

  • 文字列は strbytes を使う。
  • 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 でアクセスできる。
  • urllib は複雑にリネームされているので、 python2用 urllib を作ってしまう。

    • Python2でも普通に import urllib.request のように書ける

キモは compat_import かなと。

そうすると、以下のような感じでほぼPython3のみ対象としたのと同じソースコードになる。Python2サポートdrop時は単純なソースコード置換でいけるはず。

import urllib.request
compat_import(py2="cookielib", py3="http.cookiejar")

class Html(compatobject):
  def __init__(self, text):
    if isinstance(text, bytes):
      text = text.decode("utf8")
    self.text = text

  def __str__(self):
    return self.text

cookie_jar = http.cookiejar.MozillaCookieJar()
handlers = [urllib.request.HTTPCookieProcessor(cookie_jar)]
opener = urllib.request.build_opener(*handlers)
html = Html(opener.open("http://www.google.co.jp/").read())

ソースコードの寿命をのばすためにもボチボチこの方針で書き変えていくつもり。

comments powered by Disqus