経緯
先日、 pythonでとあるモジュールを作ったのですが、そのモジュールを別のコードでインポートしたところ、
ModuleNotFoundError: No module named 'xxx'
というエラーが発生しました。 実は、インポートしたモジュールの中で別のモジュールをインポートしていたのですが、後者のインポートがうまくいっていないようでした。
問題を再現してみた
上述の問題をわかりやすくするため、簡単なコードでエラーを再現してみました。
まずは、次に示す child1.py
と child2.py
という名前のコードを同一ディレクトリに保存します。
child1.py
import child2 def foo(): child2.bar() if __name__ == '__main__': foo()
child2.py
def bar(): print('Hello')
このコードは以下のようにして実行することが出来ます。ここまでは当たり前ですね。
$ python child1.py Hello
ここまでは何の問題もありません。
では、このchild1.pyを別のコードから呼び出してみようと思います。
呼び出し元のコードはparent.pyとします。
parent.py
from children import child1 child1.foo()
それぞれのソースの保存場所はこのような関係になっているとします。
$ tree . . ├── children │ ├── child1.py │ └── child2.py └── parent.py
ここまでの状況を整理すると下図のようになります。
では、parent.pyを実行してみましょう。
$ python parent.py Traceback (most recent call last): File "parent.py", line 1, in <module> from children import child1 File "/hogehoge/children/child1.py", line 1, in <module> import child2 ModuleNotFoundError: No module named 'child2'
エラーが出ました。child2
という名前のモジュールが見つからないと言われてしまいまいましたね。
問題の原因
上記のエラーが出た理由は、インポート先として有効なパスの中に child2.py
が含まれていなかったからです。
通常、インポート先として有効なパスは
- スクリプトファイルがあるディレクトリ
- 環境変数PYTHONPATHで指定したディレクトリ
- カレントディレクトリ
- 標準ライブラリのためのディレクトリ
- pipでインストールしたライブラリが入っているディレクトリ
の5種類です。
カレントディレクトリの下の階層を再起的に見に行ってくれるわけではないので、これでは child2.py
を参照することはできないのです。
解決策
child1.py
の中身を以下のように変更してください。
from children import child2 def foo(): child2.bar() if __name__ == '__main__': foo()
1行目だけ変更しました。
python.py
があるディレクトリの直下に children
ディレクトリが存在するので、 python.py
があるディレクトリ内で python.py
を実行すれば children
ディレクトリにはパスが通っているので、その下にある child2.py
をインポートすることができます。
ただし、これでは child1.py
があるディレクトリ内で child1.py
を実行するとエラーが起きます。
children
にパスが通っていないためです。
この問題への対策方法としては、環境変数 PYTHONPATH
に parent.py
があるディレクトリパスを設定することが有効です。
$ cd [parent.pyがあるディレクトリ] $ export PYTHONPATH=$PYTHONPATH:`pwd`
環境変数を設定後、いろいろな場所で parent.py
と child1,py
を実行してみました。
$ python parent.py Hello $ python children/child1.py Hello $ cd children $ python child1.py Hello $ python ../parent.py Hello
いずれも正しく動いています!!
本日は、多重にモジュールをインポートしたときに起きる ModuleNotFoundError: No module named 'xxx'
というエラーの原因と対策についてご紹介しました。
良い記事だと思っていただいた方は、以下の「★+」ボタンのクリック、SNSでのシェア、「読者になる」ボタンのクリック、Twitterのフォローをお願いします!