概要
自作モジュールを相対パスでimportしたく、sys.path.append(os.path.dirname(__file__)
を入れたのに何故かimportができなかった。
結論
pipで入れていたパッケージと自作モジュールで利用していた名前が被っていたため、pipで入れたパッケージを読み込みにいってしまっていた。
環境
- Windows10
- miniconda
詳細
以下のような構成で自作モジュールを呼び出そうとしたところ、libs.utils
が見つからないとModuleNotFoundError
が発生。
parent_dir/
|- my_modules/
| |- libs/
| |- utils.py
| |- my_module.py
|- controller.py
controller.py
⇒ my_module.py
⇒ utils.py
と呼び出す流れ。
各モジュールのコード
from my_modules.my_module import *
module_func()
from libs.utils import *
def module_func():
print("This is module_func")
utils_func()
def utils_func():
print("This is utils_func")
やりたいこと
parent_dir
にいる状態でpython controller.py
を実行
⇒以下のような結果が欲しい。
[自分のフォルダ]\parent_dir>python controller.py
This is module_func
This is utils_func
しかし、結果は以下の通り。
File "[自分のフォルダ]\parent_dir\my_modules\my_module.py", line 1, in <module>
from libs.utils import *
ModuleNotFoundError: No module named 'libs.utils'
原因と解決策
原因:コマンドから実行する場合、controller.py
を実行しているparent_dir
が基準になるため、parent_dir
からlibs.utils
を探しているが見つからない。
解決策:こちらの記事を参考に「モジュール探索パスを追加して絶対インポート」する方法を実践。
つまり、my_modules\my_module.py
にsys.path.append(os.path.dirname(__file__)
を追加する。
# 追加分
import os
import sys
sys.path.append(os.path.dirname(__file__))
# 追加分ここまで
from libs.utils import *
def module_func():
print("This is module_func")
utils_func()
これにより、my_moduleフォルダもパスに追加されるため、相対パスとして読み込んでくれるはず!
結果
File "[自分のフォルダ]\parent_dir\my_modules\my_module.py", line 1, in <module>
from libs.utils import *
ModuleNotFoundError: No module named 'libs.utils'
変わらない!なぜ!
現象の調査
いろいろ試してみると、自分が使っているminicondaの仮想環境でこの事象が発生することが判明。(新規作成したまっさらな仮想環境では事象が発生しない。)
試したこと
仮想環境にinstallした何かしらのパッケージが原因と考え、問題環境のinstallパッケージの一部を削除しながら原因のパッケージを特定することに。
おそらく他に効率が良いやり方があるのだろうが、知識のない私は地道な作業で調査。
※以下のコマンドはこちらを参考にさせていただきました。
①仮想環境の情報をyamlファイルに書き出す。
conda env export > ファイル名.yml
②yamlファイルのうちdependenciesを2分探索の要領で分割
③分割したyamlファイルを基に新規環境作成
conda env create -n 新たな環境名 -f ファイル名.yml
特定
そしてついに突き止めた。
dependencies:
- pip=21.2.4=pyhd8ed1ab_0
- pip:
- libs==0.0.10
このlibsが存在していると問題が発生する。
ここまでくれば原因は明確。
libs.utils
を見に行く際に、pipでinstallしているlibsを優先的に探していたということであった。
教訓
- 自作モジュールを使う場合は汎用的な命名を避ける。(my_libsのような名前にする。)
-
condaとpip:混ぜるな危険←今回は直接関係なかったが、改めて確認すると
pip install
しているパッケージが多かったと反省。