背景
Pythonで開発をしていると、main.py以外のファイルからコードを実行しようとしたときに、他階層にある関数やクラス等をimportしようとしてModuleNotFoundError
が発生することがよくあります。特にデバッグ等をするときにmain.pyへimportして実行するのは面倒です。この記事では、どの階層のファイルからでも実行できる方法を紹介します。
本記事の対象者
Python開発中でModuleNotFoundeError
地獄から抜け出したい方
エラーの原因
main.pyのようにルートにあるファイルからは実行できるのに、他の階層にあるファイルではエラーになる理由は、Python実行時のカレントディレクトリ(実行パス)に依存しているためです。
Pythonは、実行されたスクリプトの位置を基準にしてsys.pathが設定されます。そのため、importしようとしたファイルが見つからず、ModuleNotFoundErrorが発生します。
解決方法
Pathが通っていないことが原因であるため、PYTHONPATH
という環境変数にプロジェクトのルートディレクトリを明示的に追加することで解決できます。
例): devディレクトリがプロジェクトのルートであるとき
// ディレクトリ構成
dev/
└── src
├── main.py
└── service
├── hoge.py
└── piyo.py
dev
ディレクトリからimportしたい場合
# 環境変数PYTHONPATHにdevディレクトリまでのパスを追加(Pathは調整してください)
export PYTHONPATH="/Users/kikudesuyo/directory/dev:$PYTHONPATH"
# devディレクトリを起点としたimport
from dev.src.handler.piyo import handle_piyo
src
ディレクトリからimportしたい場合
# 環境変数PYTHONPATHにsrcディレクトリまでのパスを追加(Pathは調整してください)
export PYTHONPATH="/Users/kikudesuyo/directory/dev/src:$PYTHONPATH"
# srcディレクトリを起点としたimport
from src.handler.piyo import handle_piyo
*すべてのファイルで統一したimportパスを記述する必要があります。中途半端に相対パスや異なる起点としてimport文を混在させると混乱のもとになります
チーム開発でのベストプラクティス
仮想環境(venv等)を構築する場合は、bin/activate
ファイルにPYTHONPATH
を設定しておくことで、環境を有効化する度に自動で反映されます。
以下のようにactivate
スクリプトの下部に追記してください。
activateファイル(venv/bin/activateの下の方に追記させます)
export PYTHONPATH="/Users/kikudesuyo/directory/dev/src:$PYTHONPATH"
# Call hash to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
hash -r 2> /dev/null
こうすることで、チーム内の全員が共通の環境構成で開発・実行が可能になります。
※ プロジェクト全体でどのディレクトリを起点にimportを行うかを事前に決めておくことが重要です。READMEやドキュメントなどで明示しておくと、チーム内の認識齟齬を防げます。環境構築のスクリプト等に入れ込んでも良いかもしれないです。
さいごに
複雑なアプリケーションを開発する際に開発体験が大幅に向上しました。是非試してみてください!