Pythonで自作モジュールをインポートするときに、相対パスで指定する方法があります。
Pythonをそこそこ覚えてきたら、1枚ファイルにベタ書きなんてやってらんないので、当然いくつかのファイル(モジュール)に割りますよね。
そんなことをしていると、上位ディレクトリにあるモジュールを使いたくなることがめっっっっっっちゃ出てくるので、実行スクリプト内で、
1 |
from .. import hogemodule |
のように書いたんですけど、どうもこの書き方、使えないみたいです……
Pythonでは、モジュールをimportする際にsys.pathに入っているパスのリストを見ているみたいなのですが、どうもこれらのパスから上位ディレクトリに遡るような動きができないみたいです。
じゃあなんでこんな書き方サポートしたんや(´・ω・`)
参考→6. モジュール (module) — Python 3.6.5 ドキュメント
https://docs.python.jp/3/tutorial/modules.html#the-module-search-path
Python実行時に、ファイルが有るディレクトリのパスを自動的にsys.pathに挿入してくれるので、同階層のモジュールは触れるみたいです。
でも上層にあるモジュールを使いたみMAXなので、どうにかして使えるようにしてみた解決策をメモしておきます。
解決策1:sys.pathに直接パスを入れる。
sys.pathの実態はリストなので、スクリプト内でいくらでも触りたい放題です。
そこで、import前にモジュールのあるパスを直接ぶっこみます。
1 2 3 4 5 6 7 |
import sys from pathlib import Path # 上位階層のディレクトリをsys.pathに追加 sys.path.append(str(Path(__file__).parent.parent)) # 上位階層にあるモジュールをインポート import hogemodule |
__file__の親ディレクトリをappendしています。parentを2回続けているのは、1回だとファイル名を取り除くだけになってしまい、ファイルのあるディレクトリになってしまうからです。
でも、スクリプト内で直接sys.pathをいじるのはどうなんでしょう?
解決策2:一番上の階層に実行ファイルを持ってくる。
上に遡れないならば、すべてを見渡せる位置に持ってくれば問題ありません。
シンプルな解決策でいい感じですが、これだと一つの階層にたくさんのファイルがあふれることにもなりかねません。それでも良いぐらい小さなプロジェクトなら問題ないですが、それならそもそもモジュール分けする必要もないかも……
解決策3:実行時、PYTHONPATHにパスを挿入する。
多分このやり方が一番いい感じなのではないでしょうか??
リファレンスにも書いてありましたが、実行時にはPYTHONPATHの値もsys.pathに含めてくれるみたいです。
そこで、pythonコマンドを実行する前にPYTHONPATHの値を書き換えれば、スクリプトを汚さずにsys.pathをコントロールできます。
1 |
cmd /C "set "PYTHONPATH=C:\Users\nisihunabasi\repository\hoge-project" && python hoge_script.py " |
この手の実行環境構成の変更は、VSCodeだと簡単にできますね。
プロジェクト内の.vscode/launch.jsonで、使用中のビルド構成に環境変数を書き加えます。
1 2 3 4 5 6 7 8 9 |
{ "name": "Python: Current File", "type": "python", "request": "launch", "program": "${file}", "env": { "PYTHONPATH": "${workspaceFolder}" } } |
まとめ
Pythonよくわからん
VSCodeまじ神
https://code.visualstudio.com/