Python 2.6以降で作ったコードを 2.5へ対応するときに引っかかる点

python-specfor · PyPI を作るとき、Python2.6と3.1を中心に書いてました。
これを2.5にも対応させたのですが、そのときその差が意外と大きかったのが新鮮だったのでメモ。

with文

2.5では、with文を有効にするには、そのファイルで__future__指定する必要があります。

from __future__ import with_statement

これは今回の中で一番分かりやすかった違いですが、specfor自体がwith文を使わせるものであるため、そこそこ多くのファイルに埋めこむことになりました。

namedtuple

collections.namedtupleも2.6からの機能です。
自らはnamedtuple型を定義しなかったのですが、標準モジュールのほうで結構使っていて、それに依存したコードがありました。

対策A: 代入時tuple展開
# difflib.SequenceMatcher.get_matching_blocks()の戻り値 macthesにて
for match in matches:
    vindex = match.a + match.size

を以下のようにする

# difflib.SequenceMatcher.get_matching_blocks()の戻り値 macthesにて
for a, b, size in matches:
    vindex = a + size
対策B: classを作る

matchはループ中でのみ使うものだったので、展開するのが楽です。
しかし、tupleを持ち運んで使っている場合もあって、その場合には、同じインタフェースを持ったclassを作成しました。

class funcspec(object):
    def __init__(self, argspec):
        self.args, self.varargs, self.keywords, self.defaults = argspec
        pass
    pass

def getargspec(func):
    import inspect
    return funcspec(inspect.getargspec(func))

argspecがnamedtupleですが、それをfuncspecクラスで同じ名前のメンバーとなるよう調整しています。

相対import

python2.5は2.6以降にくらべ、相対importの能力が低いです。

from .framework import * # 2.5ではここで*は使えない。
# 2.5の場合、__main__モジュールでは、-mオプション経由の起動でも、相対importが使えない
from . import version

def main():
    ...

if __name__ == "__main__": main()

これは、以下のように対策しました

from .framework import spec # 個別の名前で指定する
# main内で、絶対importを使う
def main():
    from specfor import version
    ...

if __name__ == "__main__": main()