相対インポート構文が使えない

プログラムが長くなると、すべての処理を 1 つのファイルに書くのではなく、 いくつかのまとまりに分割したくなります。そうすることで見通しが良くなり メンテナンス性が上がります。また、分割して部品化しておくと、 次にプログラムを書く時にその部品を再利用しやすくなります。

この分割したファイルのことを、 Python インタプリタから直接実行される 「スクリプト」と区別して「モジュール」と呼びます。 モジュールはスクリプトからインポートすることができます。

例えば、スクリプト中に以下のような行があると、カレントディレクトリまたは モジュール検索パスの中で X.py という名前のファイルが検索され、 見つかったファイルがモジュールとしてインポートされます。

import X

モジュールは階層構造を持つことができます。これまでの記事でも階層的な モジュール名として xml.domxml.etree が出てきました。 また、いくつかのモジュールをまとめたものをパッケージと呼びます。 パッケージは多くの場合階層構造を持つモジュール群から構成されます。

モジュールはスクリプトからインポートされるだけでなく、 他のモジュールからインポートされることもあります。 そのときに関係してくるのが相対インポートと絶対インポートです。

A.B.C というモジュールで import X と書いた場合、 Python 2.4 ではこれが X というトップレベルのモジュールを指すのか(絶対インポート)、 同階層にある A.B.X というモジュールを指すのか(相対インポート)が曖昧でした。 このせいで、パッケージ内部に追加されたモジュールが標準ライブラリを隠してしまい、 これまで動いていたコードが動かなくなる、という事故が起きていました。

Python 3 [1] からは絶対インポートがデフォルトになり、 import X は常にトップレベルを指すように変更されました。 パッケージ内で相対インポートを行う場合は以下のように書く必要があります。

from . import X

Python 2.5 以降でもこの書き方は有効です。 また、次の1行を書くことで絶対インポートがデフォルトになります。

from __future__ import absolute_import

Python 2.4 では相対インポート構文は使えません。

[1]

この変更の元になった PEP 0328 では Python 2.7 から導入されることに なっていましたが、色々あって Python 3 からの導入になったようです。


不幸にして Python 2.4 で相対インポートの問題に遭遇した場合、 以下のようにして検索パスを書き換えることで問題を回避することができます。

import os
import sys

path = os.path.dirname(os.path.abspath(__file__))
try:
    sys.path.remove(path)
except ValueError:
    pass

とはいえ、これは最後の手段です。通常は問題を起こしているモジュールの名前を 変えるのが良いと思います。