今回は、Pythonで相対パスを使ってimportする方法についてご紹介します。
Pythonで相対パスを使ったimportを行うことで、パッケージ内のモジュール同士の関係を簡潔に記述できます。
パッケージ名が変わった場合にも修正箇所を最小限に抑えられるなど、多くのメリットが存在します。
ただし、実行環境やパッケージ構造を正しく理解していないと、思わぬエラーが発生することもあります。
相対インポートとは
相対インポートとは、現在のパッケージ構造を基準にして、モジュールを読み込む方法です。
「.」は現在のパッケージを、「..」は一段階上のパッケージを示します。
これにより、同じパッケージ内や上位階層のモジュールを指定できます。
相対インポートの大きな利点は、モジュール同士の依存関係が明確になり、フォルダ名やパッケージ名を変更した際の影響範囲を小さくできることです。
基本的な使い方
相対インポートでよく使われるパターンは、以下の2種類です。
- 同一パッケージにあるモジュールをインポート(.)
- 上位パッケージにあるモジュールをインポート(..)
同一パッケージからのインポート
同一パッケージのモジュールを利用する場合、先頭に「.」を付けます。
例えば、同じディレクトリにあるmodule_a.pyからsome_functionをインポートするときは、以下のように記述します。
1 |
from .module_a import some_function |
上位パッケージからのインポート
一段階上のパッケージ、またはそれ以上の階層にあるモジュールを読み込みたい場合は、ドットの数を増やします。
例として、一段階上にあるmodule_a.pyからsome_functionをインポートする場合は、以下のように書きます。
1 |
from ..module_a import some_function |
具体例
ここでは、単一パッケージ内と複数階層のパッケージ構造を例に解説します。
単一パッケージ内での相対インポート
以下のようなディレクトリ構造を想定します。
- myproject/
- mypackage/
- __init__.py
- module_a.py
- module_b.py
- mypackage/
まず、module_a.pyを以下のように定義するとします。
1 2 |
def greet(): print("Hello from module_a!") |
そして、module_b.pyでは同じパッケージ内のmodule_aからgreet関数を相対インポートして利用します。
1 2 3 4 5 6 7 8 |
from .module_a import greet def run(): print("Running module_b...") greet() if __name__ == "__main__": run() |
このmodule_b.pyを実行すると、以下のような結果が得られます。
Running module_b…
Hello from module_a!
複数階層のパッケージ内での相対インポート
次に、mypackageディレクトリの下にさらにsubpackageというディレクトリを用意した構造を考えます。
- myproject/
- mypackage/
- __init__.py
- module_a.py
- subpackage/
- __init__.py
- module_c.py
- mypackage/
親パッケージのmodule_a.pyにwelcome関数があるとします。
1 2 |
def welcome(): print("Welcome from module_a!") |
子ディレクトリのmodule_c.pyで、このwelcome関数を相対インポートする例は以下のとおりです。
1 2 3 4 5 6 7 8 |
from ..module_a import welcome def execute(): print("Executing module_c...") welcome() if __name__ == "__main__": execute() |
ただし、直接python module_c.pyと実行すると、相対インポートがうまく機能しない場合があります。
正しく動かすには、プロジェクトのルートディレクトリ(myproject)から以下のコマンドを実行してください。
1 |
python -m mypackage.subpackage.module_c |
よくあるエラーと注意点
相対インポートには、いくつか注意するポイントがあります。
- トップレベルからの実行
相対インポートはパッケージの一部として実行される場合にのみ機能します。
スクリプトとして直接実行すると、ValueErrorやImportErrorが発生することがあります。
- __init__.pyが必要
Pythonでは、ディレクトリをパッケージとして認識させるために__init__.pyを配置します。
このファイルがないと、相対インポートが正常に動作しない場合があります。
- 可読性への配慮
ドットの数が多い相対インポートを乱用すると、どの階層を参照しているのかが分かりづらくなることがあります。
必要に応じて絶対インポートとの併用を検討してください。
- Pythonバージョン
Python 3以降では相対インポートの仕様が明確ですが、古いバージョンでは挙動が異なる場合があります。
できるだけ新しいバージョンのPythonを使用すると安全です。
まとめ
相対インポートを活用すると、パッケージ内の依存関係を明確にしつつ、メンテナンス性を高めることができます。
実行環境を整え、パッケージの階層構造を正しく把握しておくと、エラーを防ぎやすくなります。
状況に応じて絶対インポートとの使い分けを検討しながら運用してみてください。