Pythonプログラマがしばしば遭遇する問題に、import したいモジュールやパッケージが見つからないというものがあります。

>>> import foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'foo'

この問題の解決の第一歩は、Pythonインタプリタがインポートするモジュールやパッケージを探す場所は sys.path という変数に格納されているということを理解することです。 この変数の形式はリストです。

例えば、私の手元にある Ubuntu 14.04 では

$ /usr/bin/python3
>>> import sys
>>> print(sys.path)
['', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', 
    '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages',
     '/usr/lib/python3/dist-packages', '/usr/lib/python3.4/dist-packages']
>>> print(len(sys.path))
7

となります。sys.path に含まれるパスは デフォルトでロードされる site というパッケージに大きく影響されます。 Pythonインタプリタ起動時に、-Sというオプションを付けると、site パッケージをロードしないようにできます。 手動で siteimport してみると sys.path の中身が増えているのがわかります。

$ /usr/bin/python3 -S
>>> import sys
>>> print(sys.path)
['', '/usr/lib/python3.4/', '/usr/lib/python3.4/plat-x86_64-linux-gnu', 
    '/usr/lib/python3.4/lib-dynload']
>>> print(len(sys.path))
4
>>> import site
>>> print(len(sys.path))
7

sys.path[0]、つまりこのリストの先頭にはPythonインタプリタを起動するときに与えられたPythonスクリプトのディレクトリが入ります。したがって起動したスクリプトのあるディレクトリは、importの検索対象になります。 Pythonインタプリタが対話的に起動された場合、sys.path[0]は空になります。これはカレントディレクトリ(現在位置)を意味します。

環境変数 PYTHONPATH の値は、起動時に sys.path に挿入されます。ただし、挿入される場所は sys.path[0] の直後である点に注意しましょう。

$ export PYTHONPATH="/foo/bar/baz"
$ /usr/bin/python3
>>> import sys
>>> print(sys.path)
['', '/foo/bar/baz', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', 
    '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', 
    '/usr/lib/python3/dist-packages', '/usr/lib/python3.4/dist-packages']

sys.path は変更可能です。たとえば以下のようにして、Pythonスクリプトの中から、任意のディレクトリを、import のサーチパスに追加することができます。

>>> sys.path[0:0]=['/my/python/dir']
>>> print(sys.path)
['/my/python/dir', '', '/foo/bar/baz', '/usr/lib/python3.4', ...

参考URL

野中 哲

野中 哲

エンジニア、開発担当

2016年3月に入社。NECで衛星通信の制御用ソフト開発、アップルでMacOSのローカリゼーション、AppleShareファイルサーバの開発等に従事。プライベートではRuby,Haskellなどのプログラミングとラグビー観戦を好む。最近の興味はSwiftでiOSアプリを開発すること。FAA自家用パイロットライセンス所有。