pipでモジュールを確かにインストールしたはずがModuleNotFoundErrorと出た時の解決法初心者的理解


1.pipでモジュールを確かにインストールしたはずが…

ファイルやフォルダを削除する際に完全削除ではなく、ゴミ箱に移す機能を持つモジュール"send2trash"をインタラクティブシェルでインポートしようとしたら以下のようなエラーがでました。

エラー画面
>>> import send2trash
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    import send2trash
ModuleNotFoundError: No module named 'send2trash'

「そんなモジュールは無ぇ!」と怒られてしまいました。
確かにpipでインストール済なのに。。念の為もう一回インストールしてみます。

インストール再挑戦
Yuto-Mac:~ yutoman$ pip install send2trash
Requirement already satisfied: send2trash in /Users/yutoman/.pyenv/versions/3.7.3/lib/python3.7/site-packages (1.5.0)

「もうあるよ。」と言われてしまいました。

よく読んでみると、どうやら"/Users/yutoman/.pyenv/versions/3.7.3/lib/python3.7/site-packages"という場所にインストールされているようです。

ということはPython君はこのパスを見ないで「そんなモジュールは無ぇ!」と怒っているようです。メガネを頭上に載せて「オレのメガネが無ぇ!」と騒ぐおっちゃんみたいですね。優しく気づかせてあげましょう。

2.importする時いつもどのパスを見に行っているのだろう?

importする時にいつもどこを見に行っているか確認します。なぜなら、そこにモジュールそのもの、もしくはモジュールの在り処を書いたメモがあれば、きっとPython君はモジュールの存在に気づいてくれるはずだからです。

まあ「そんなモジュールは無ぇ!」と怒っているということは、多分無いのでしょう…。

さて、Python君がモジュールの検索の際に見ているパスのリストは
"sys.path"に格納されているとのことですので、表示してみましょう。

いつも見に行っているパス
>>> import sys, pprint
>>> pprint.pprint(sys.path)
['',
 '/Users/yutoman/Documents',
 '/Library/Frameworks/Python.framework/Versions/3.7/lib/python37.zip',
 '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7',
 '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload',
 '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages']

案の定、
"/Users/yutoman/.pyenv/versions/3.7.3/lib/python3.7/site-packages"は書いてなかったですね。
という訳で、このパスをsys.pathに追加してあげればOKです。

3.pthファイルを作成して既存のパスに仕込む!

pthファイルという便利なファイルがあります。
このファイルにパスを書くことで、そのパスがモジュールの検索パスとして扱われるというものです。

このpthファイルを使って
モジュールの在り処を書いたメモを作って、いつも見に行っているパス上に置いておこうと思います。

置き場はどこでも良いと思ったのですが、"site-packages"はサードパーティのモジュールが置かれるディレクトリらしいのでこちらにファイルを置いておきます。

pthファイルを設置したいディレクトリに移動して、vimからファイルを新規作成します。(今回ファイル名は"importmodule.pth"としました。)

vimを開く
Yuto-Mac:~ yutoman$ cd /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages
Yuto-Mac:site-packages yutoman$ vim importmodule.pth 

空のpthファイルにモジュールの在り処"/Users/yuto0593/.pyenv/versions/3.7.3/lib/python3.7/site-packages"を書いておきます。

vimを編集する
/Users/yuto0593/.pyenv/versions/3.7.3/lib/python3.7/site-packages

":wq"でファイルの上書き保存の上vimから抜けて完了です。

4.うまくいった!

インポートをリトライする前に、Pythonのインタラクティブシェルを一回閉じてもう一度開き直しましょう。(再起動)
それではもう一度、"sys.path"の中身を見てみます。

いつも見に行っているパス
>>> import sys, pprint
>>> pprint.pprint(sys.path)
['',
 '/Users/yuto0593/Documents',
 '/Library/Frameworks/Python.framework/Versions/3.7/lib/python37.zip',
 '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7',
 '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload',
 '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages',
 '/Users/yuto0593/.pyenv/versions/3.7.3/lib/python3.7/site-packages']

"/Users/yuto0593/.pyenv/versions/3.7.3/lib/python3.7/site-packages"が最後の行に追加されています!

インポートしてみると…。

インポート
>>> import send2trash
>>> 

エラー無くインポートできました!

5.参考ページとか

僕もそうなのですが、初学者は特に、エラーで先に進めなくなると心が挫けそうになりますよね。。萎えちゃうというか。。
でもそれってとてももったいないと思うので、先輩方の過去投稿と自分なりのトライアンドエラーからわかりやすく解決方法をまとめて同じような初学者の皆様に貢献できたらな、とこの記事を書きました。

ちなみにこの方法は、自分で作ったモジュールをインポートさせる時にも活用できるみたいですね!!

以下、参考にさせていただいたページです。ありがとうございました。
[Python] ModuleNotFoundError解決方法
<python>モジュールの場所
Pythonでimportの対象ディレクトリのパスを確認・追加(sys.pathなど)