[Python]別ディレクトリの自作モジュールをimport

Python

Pythonがモジュールを検索する流れをざっくりと把握してから、別ディレクトリにあるモジュールのパスを通す方法を見ていきます。

パスを通す場所というのは3つあるのですが、その場所というのは、

  • sys.path
  • .pthファイル
  • 環境変数のPYTHONPATH

です。

このいずれかにパスを記述します。
以下で詳しくやっていこうと思います。

使用した環境
Windows10
Docker Python 3.9.0[Debian]
Python 3.10.5

スポンサーリンク
スポンサーリンク

モジュールの検索

import文があったときに、Pythonはビルトインモジュール(一部・・の標準ライブラリ。sysなど)を検索し、見つからなかったときにsys.path(リスト)に入っているパスから順に探していきます。
6.1.2. モジュール検索パス

いちどsysをインポートし、sys.pathを確認してみましょう。

コンソール画面

$ docker run -it --rm python
Python 3.9.0
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/local/lib/python39.zip', '/usr/local/lib/python3.9', '/usr/local/lib/python3.9/lib-dynload', '/usr/local/lib/python3.9/site-packages']

私の環境では上のようになりました。

環境によってディレクトリの構成が異なるかもしれませんが、
「'/usr/local/lib/python3.9'」には、ramdomやdatetimeなどの標準ライブラリが入っています。
「'/usr/local/lib/python3.9/site-packages'」には、任意でインストールしたモジュールがあります。

リスト先頭の「''」はカレントディレクトリです。
もしモジュールから実行した場合、先頭にはそのモジュールの入っているディレクトリのパスが入ります。

ちょっとやってみましょう。

/code/test.py

import sys


print(sys.path)

コンソール

$ python /code/test.py 
['/code', '/usr/local/lib/python39.zip', '/usr/local/lib/python3.9', '/usr/local/lib/python3.9/lib-dynload', '/usr/local/lib/python3.9/site-packages']

モジュールの中でsys.pathを表示させると、上記リストの一番目が「'/code'」になっています。

カレントディレクトリ内にモジュールがあるときや、pipでインストールしたものなどはパスが通っていますが、それ以外の場合は、パスを追加する必要があります。

カレントディレクトリ内にあるモジュール・パッケージの呼び出し方↓

パスを通すには

Pythonにパスを通すには、これから挙げる3つのどれかにパスを書きます。

  • sys.path
  • .pthファイル
  • 環境変数のPYTHONPATH

これからひとつずつやっていきますが、共通事項として、モジュールのファイル名が「mymodule.py」、モジュールを収めているディレクトリのパスが「/mypackage」とし、カレントディレクトリのパスが「/code」として作業を進めます。

ファイル構成のイメージ

ルートの下に2つのディレクトリ「code」と「mypackage」があり、mypackage配下にmymoduleがある。

mymodule.py

print('from mymodule')

インポートに成功すると、「from mymodule」と表示させるシンプルなモジュールです。

そもそもパスについてよく分からないという人は先に↓を参考にしてください。

sys.path

sys.pathはリストなので、メソッドのappendを使ってパスを追加することができます。

import sys
sys.path.append('ディレクトリのパス')

さっそくやってみようと思います。

コンソール画面

Python 3.9.0
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path.append('/mypackage')
>>> sys.path
['', '/usr/local/lib/python39.zip', '/usr/local/lib/python3.9', '/usr/local/lib/python3.9/lib-dynload', '/usr/local/lib/python3.9/site-packages', '/mypackage']

リストの末尾に'/mypackage'が追加されていますね。
モジュールをインポートします。

>>> import mymodule
from mymodule

「/mypackage」へのパスが通っているので、中に入っているmymoduleをインポートすることに成功しました。

ただしsys.pathへの追加は一時的なものです。

Pythonを一度終了し、再びmymoduleをインポートしようとするとエラーになります。

Python 3.9.0
Type "help", "copyright", "credits" or "license" for more information.
>>> import mymodule
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'mymodule'
>>> import sys
>>> sys.path
['', '/usr/local/lib/python39.zip', '/usr/local/lib/python3.9', '/usr/local/lib/python3.9/lib-dynload', '/usr/local/lib/python3.9/site-packages']

sys.pathに「'/mypackage'」はありません。

実行モジュール内で「sys.path.append」することで別ディレクトリのモジュールを使えるようにはなります。

実行用モジュールを新規作成
/code/main.py

import sys
sys.path.append('/mypackage')
import mymodule

コンソール画面

python main.py
from mymodule

mainのコードでは、sysを呼んでからリストに追加し、次の行でようやく呼び出したいモジュールをインポートしています。

これはPEP8 - Style Guide for Python[Imports]に反しているので、気になる方はいるでしょうし、モジュールを公開する場合に推奨する方法ではありません。

.pthファイル

拡張子が「.pth」のファイルを作成します。ファイルを保存する場所は、sitepackagesのなかです。

まずsitepackagesの場所を確認しましょう。

sys.pathで確認してもいいですが、今回はPythonを起動して以下を実行します。

import site
site.getsitepackages()

Python 3.9.0
>>> import site
>>> site.getsitepackages()
['/usr/local/lib/python3.9/site-packages']

私の環境では'/usr/local/lib/python3.9/site-packages'と出ました。
そのディレクトに移動します。

ファイルを作成し、追加したいパスを書きます。
複数のパスを追加したい場合、改行して一行ずつ記入してください。
拡張子を.pthにします。

test.pth
※ファイル名は自身がわかりやすければ何でも構いません

/mypackage

確認のため実行します。

Python 3.9.0
>>> import mymodule
from mymodule

printがちゃんと実行されていますね。

環境変数・PYTHONPATH

環境変数名「PYTHONPATH」にパスを入れます。

Unix系とWindowsで分けて説明。

Unix系

コンソールから、
export PYTHONPATH=ディレクトリのパス で行います。
複数のパスを追加したい場合、パスとパスの間を:(コロン)でつなぎます。

$ export PYTHONPATH=/mypackage
$ python
Python 3.9.0
>>> import mymodule
from mymodule
>>> import sys
>>> sys.path
['', '/mypackage', '/usr/local/lib/python39.zip', '/usr/local/lib/python3.9', '/usr/local/lib/python3.9/lib-dynload', '/usr/local/lib/python3.9/site-packages']

PYTHONPATHで書いたパスは、sys.pathのリストの2番目に追加されていますね。

ただしこちらの方法も一時的なものなので、常時有効にするには、.bashrcに書いておきましょう。

また一度作成したPYTHONPATHにパスを追記したいときには以下のように書きます。

export PYTHONPATH=$PYTHONPATH:追加したいディレクトリのパス

Windows

Windowsでは「コマンドプロンプト」と「PowerShell」でコマンドが異なります。

自身の使っている方を選んでください。

コマンドプロンプトPowerShell
set PYTHONPATH=フォルダのパス$env:PYTHONPATH="フォルダのパス"

確認するにあたってフォルダの構成が変わります。

「C:\Users\fujino\Documents\」のなかに「code」と「mypackage」フォルダがあり、「mypackage」に「mymodule.py」があるものとします。

作業フォルダは「code」です。

コマンドプロンプトでパスを通します。

>set PYTHONPATH=C:\Users\fujino\Documents\mypackage
>py
Python 3.10.5 (tags/v3.10.5:f377153, Jun  6 2022, 16:14:13) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import mymodule
from mymodule
>>> import sys
>>> sys.path
['', 'C:\\Users\\fujino\\Documents\\mypackage', # 以下略]

PowerShellの場合です。

> $env:PYTHONPATH="C:\Users\fujino\Documents\mypackage"  
> py
Python 3.10.5 (tags/v3.10.5:f377153, Jun  6 2022, 16:14:13) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import mymodule
from mymodule

ここで設定した環境変数も一時的なものです。

環境変数への保存(永続化)[Microsoft Docs]

まとめ

モジュール検索の流れと、パスを追加する3つの場所について見てきました。

モジュール検索はビルトインモジュール、sys.pathのリストの中から順に行われる

sys.pathにappendメソッドでパスを追加

sitepackagesのなかに拡張子.pthのファイルを作成してパスを記入

環境変数PYTHONPATHを定義して追加する

タイトルとURLをコピーしました