モジュールとパッケージ
モジュールのインポート
モジュールとは、「モジュール.py」というPythonのスクリプトファイルのことです。モジュールに定義されるクラスや関数、グローバル変数を再利用可能な「ライブラリ」としてスクリプトから利用できます。
モジュールはimport文により、モジュール名を指定してスクリプトにインポートします。これは通常、スクリプトの最初に宣言します。
import モジュール名, モジュール名, ...
import モジュール名
import モジュール名
...
インポートしたモジュールの内容は、スクリプトの中で利用できます。モジュール名を名前空間として、モジュールに定義されたクラス、関数、変数を参照できます。
モジュール名.クラス
モジュール名.関数()
モジュール名.変数
例えば、次のmodule1.pyに文字列変数とクラス、関数を定義して、これをモジュールとします。
module1.py
mo_str = "Module1 ABC"
def mo_func():
print("Module1 func")
class CMo:
def msg(self):
print("Module1 Class")
module1.pyと同じディレクトリ(フォルダ)のスクリプトで、module1.pyをインポートして利用します。
import module1
print(module1.mo_str)
module1.mo_func()
mod1 = module1.CMo()
mod1.msg()
Module1 ABC
Module1 func
Module1 Class
モジュールを複数用意して、それらを同時にインポートして利用できます。上のmodule1.pyに加え、別のモジュールmodule2.pyを次のように作成します。
module2.py
mo_str = "Module2 ABC"
def mo_func():
print("Module2 func")
class CMo:
def msg(self):
print("Module2 Class")
そしてmodule1とmodule2を両方インポートすると、両方の機能を使うことができます。
import module1, module2
print(module1.mo_str)
module1.mo_func()
mod1 = module1.CMo()
mod1.msg()
print(module2.mo_str)
module2.mo_func()
mod2 = module2.CMo()
mod2.msg()
Module1 ABC
Module1 func
Module1 Class
Module2 ABC
Module2 func
Module2 Class
複数のインポートを個別のimport文にしてもかまいません。
import module1
import module2
ユーザが作成したモジュールは、原則としてimportを宣言しているスクリプトと同じディレクトリ階層に置く必要があります。Python環境には、正規表現のreや数学関数のmathのような多くのモジュールがインストールされてます。import文は、最初にインポート対象のモジュールがインストール済みライブラリにあるかどうかを検索し、そこになければ、実行中のスクリプトと同じディレクトリ階層を探します。
モジュールを別名で使う
import文のモジュール名に続けて「as 別名」のように指定すると、インポートするモジュールを別名で参照できるようになります。
import モジュール名 as 別名
スクリプト内で別名は重複できません。
次の例は、上の例のmodule1とmodule2モジュールをそれぞれ「m1」「m2」という短い名前の別名で参照しています。
import module1 as m1, module2 as m2
m1.mo_func()
m2.mo_func()
Module1 func
Module2 func
モジュール名の省略
from~import文により、モジュールから参照したいシンボル名(関数、クラス、変数)を選択してインポートできます。
from モジュール名 import 関数, クラス, 変数等, ...
この場合、選択したシンボル名を参照するときの「モジュール名.〜」のモジュール名を省略して、そのままの関数名やクラス名で使うことができます。
次の例は、上の例で使ったmodule1、module2モジュールをインポートし、module1からCMoクラス、module2からはmo_func()関数、mo_str変数を選択してインポートしています。これらの参照時に、module1.やmodule2.を付ける必要がなくなります。
from module1 import CMo
from module2 import mo_func, mo_str
m = CMo()
m.msg()
mo_func()
print(mo_str)
Module1 Class
Module2 func
Module2 ABC
選択するシンボル名を「*」とすると、そのモジュール内の全てを一括指定できます。その場合、そのモジュールを使うときの「モジュール名.〜」が全て不要になるので、そのモジュールの記述を現在のスクリプトに含めた(写した)ようになります。
from モジュール名 import *
次の例は、module2をform~importでインポートしています。「module2.~」は不要になります。
from module2 import *
m = CMo()
m.msg()
mo_func()
print(mo_str)
Module2 Class
Module2 func
Module2 ABC
モジュールのパッケージ化
ユーザ定義のモジュールの置き場所は、デフォルトではインポートする側のスクリプトと同じディレクトリ(フォルダ)内としていますが、同じ目的や機能を持つ複数のモジュールを、ディレクトリ(フォルダ)の配下に格納しパッケージとしてまとめることができます。このとき格納するディレクトリ名がパッケージ名となります。
パッケージとするディレクトリには、モジュールの.pyファイルと共に、__init__.pyというファイルを配置する必要があります。__init__.pyが存在により、そのディレクトリがパッケージとして認識されます。
例として、次のようなディレクトリ構造で、mod1モジュールを含めたpack1パッケージを作成し、test.pyからpack1パッケージのmod1モジュールをインポートするとします。
┣ test.py
┗ pack1/ pack1パッケージ
┣ __init__.py => この例では中身は空でよい
┗ mod1.py mod1モジュール
mod1モジュールにはfunc()関数を実装します。
pack1/mod1.py
def func():
print("pack1 mod1 func()")
test.pyは、pack1パッケージのmod1をインポートします。このとき「パッケージ名.モジュール名」のように指定します。
import パッケージ名.モジュール名
そしてmod1のfunc()を呼び出すときは、パッケージ名とモジュール名を名前空間として指定します。
パッケージ名.モジュール名.クラス
パッケージ名.モジュール名.関数()
パッケージ名.モジュール名.変数
test.pyでは、次のようにpack1パッケージのmod1モジュールのfunc()を呼び出すことができます。
test.py
import pack1.mod1
pack1.mod1.func()
pack1 mod1 func()
これは、from~importで次のようにもできます。
test.py
from pack1 import mod1
mod1.func()
test.py
from pack1.mod1 import func
func()
この例は実際は、Python3.3以降ならば__init__.pyがなくても同じ結果になります。__init__.py存在しないディレクトリは「名前空間パッケージ」という、通常のパッケージとは少し異なる特徴があります。
パッケージ名でモジュールをインポート
上の例の__init__.pyは中身が空で、ファイルの存在でパッケージであることを示す以外に役割はありませんでした。モジュールをディレクトリ階層ごと指定しているだけで、パッケージにした意味が感じられません。
モジュールをパッケージにまとめるならば、パッケージ名だけでインポートして利用できるべきです。
import パッケージ名
そのようなパッケージを構成するために、__init__.pyに記述したものは、特別にパッケージ名で参照できるという仕組みがあります。
例として、次のようにpack1下の__init__.pyに関数func()を実装します。
┣ test.py
┗ pack1/
┗ __init__.py
pack1/__init__.py
def func():
print("pack1 __init__ func()")
pack1パッケージを利用するtest.pyでは、「import pack1.__init__」ではなく「import pack1」でインポートし、pack1の名前空間としてfunc()を呼び出すことができます。
test.py
import pack1
pack1.func()
pack1 __init__ func()
相対インポートでモジュールをまとめる
実際のパッケージは __init__.pyに全て実装するのではなく(それでは単体モジュールと変わらない)、いくつかのモジュールをディレクトリにまとめてパッケージとするものと思います。
次のようなmod1.pyの実装をpack1パッケージとして含めたい場合を考えます。
┣ test.py
┗ pack1/
┣ __init__.py
┗ mod1.py
__init__.pyは、スクリプトが「import パッケージ名」でインポートするときに評価されます。なので、__init__.pyの中でモジュールmod1.pyをインポートすれば、モジュールを連なるようにパッケージに取り入れることができます。
pack1/__init__.py
from .mod1 import func
pack1/mod1.py
def func():
print("pack1 mod1 func()")
pack1パッケージを利用するtest.pyでは、pack1のインポートのみでmod1.pyの関数を呼び出すことができます。
test.py
import pack1
pack1.func()
pack1 mod1 func()
ところで、__init__.pyの「from .mod1」に付いている「.」は現在のディレクトリを指定するものです。__init__.pyにとってmod1.pyは同一ディレクトリなので、
from mod1 import func
でもよさそうですが、実際は次のようにエラーになります。
ModuleNotFoundError: No module named 'mod1'
__init__.pyのimportでmod1が見つからないという意味ですが、importにおける現在のディレクトリというのは「pythonコマンドを実行した場所」となっているため、この場合は「pack1.mod1」が正しい階層になります。実際に__init__.pyを次のようにすればエラーになりません。
from pack1.mod1 import func
しかし、インポート側とパッケージがいつもこの位置関係とは限らないので、現在のモジュールから見た相対的な同一階層を「.」とできるようになっています。
次のように「from .」として、続くimportが現在ディレクトリからの相対インポートであることを示すこともできます。この場合のtest.pyでは、パッケージのインポートはpack1のみの指定ですが、func()の呼び出しではpack1.mod1の指定が必要になります。
pack1/__ini__.py
from . import mod1
test.py
import pack1
pack1.mod1.func()
モジュール間の相対インポート
__init__.pyからのインポートだけでなく、モジュール同士でも相対インポートができます。次のように、pack1パッケージにmod1とmod2モジュールがあるとします。
┣ test.py
┗ pack1/
┣ __init__.py
┣ mod1.py
┗ mod2.py
__init__.pyからmod1を相対インポートして、さらにモジュール同士でmod1.pyからmod2.pyを相対インポートするとします。
pack1/__ini__.py
from .mod1 import func
pack1/mod1.py
from . import mod2
def func():
mod2.func()
pack1/mod2.py
def func():
print("pack1 mod2 func()")
pack1パッケージをインポートしたtest.pyでpack1.func()を呼び出すと、その結果はmod2.pyのfunc()を呼び出すことになります。
test.py
import pack1
pack1.func()
pack1 mod2 func()
現在の上位階層への相対インポート
相対インポートは、現在ディレクトリの上の階層を「..」で指定できます。
次のようなパッケージ構成で、pack1パッケージは上階層のmod0を相対インポートしています。
┣ test.py
┗ pack0/
┣ __init__.py
┣ mod0.py
┗ pack1/
┗ __init__.py
pack0/mod0.py
def func():
print("pack0 mod0 func()")
pack0/pack1/__init__.py
from .. import mod0
test.pyはpack0.pack1パッケージをインポートし、pack1ではなくpack0の下のmod0.pyの関数func()を呼び出すことができます。
test.py
from pack0.pack1 import mod0
mod0.func()
ところでこの例は、次のようなもっと簡単な構成にして、pack0パッケージから上階層のmod0.pyを相対インポートすれば済むのではないでしょうか。
┣ test.py
┣ mod0.py
┗ pack0/
┗ __init__.py
ところがこれはエラーになります。相対インポートは「pythonコマンドを実行する階層を通ることができない」という規則があるからです。test.pyと同じ位置のmod0.pyへの相対インポートはできないのです。
「import *」の対象の選択
モジュールを「from ~ import *」のようにインポートするとき、「*」はデフォルトでモジュール内のすべてが対象になりますが、__all__リストに設定することで、インポート対象を限定することができます。
例えば、次のようにmod1モジュールにfunc1()とfunc2()の関数定義がある場合、
mod1.py
def func1():
print("mod1 func1()")
def func2():
print("mod1 func2()")
mod1.pyのインポートを「from mod1 import *」のようにすれば、通常はどちらの関数もモジュールから参照できますが、その前に__all__のリストに"func1"のみを与えると、「*」の該当はfunc1のみとなり、func2()を呼び出してもエラーになります。
test.py
__all__=["func1"]
from mod1 import *
func1()
func2()
mod1 func1()
NameError: name 'func2' is not defined. Did you mean: 'func1'?
パッケージ「*」のインポート選択
パッケージの場合は振る舞いが逆になり、パッケージで__all__を設定していなければ、パッケージ内のモジュールは全て対象から外れます。つまり、パッケージから「from パッケージ import *」でインポートしてもよいモジュールを、__all__で設定しておく必要があります。
例えば次のようなpack1パッケージの構成で、test.pyがインポートするpack1パッケージにはmod1も含まれるように思えますが、実際はmod1の未定義エラーになります。
test.py
pack1/
┣ __init__.py =>空のファイル
┗ mod1.py
pack1/mod1.py
def func():
print("pack1 mod1 func()")
test.py
from pack1 import *
mod1.func()
NameError: name 'mod1' is not defined
これは、__init__.pyに次を追加すればmod1を呼び出すことができるようになります。
pack1/__init__.py
__all__=["mod1"]
名前空間パッケージ
次のように、離れたディレクトリに同じ名前のパッケージが存在するとき、Pythonシステムのパッケージ検索パスにdir1とdir2以下を追加して、両方のpack1パッケージのインポートを試みるとします。
dir1/
┗ pack1/
┣ __init__.py
┗ mod1.py
dir2/
┗ pack1/
┣ __init__.py
┗ mod2.py
mod1とmod2は以下の実装とします。
dia1/pack1/mod1.py
def func1():
print("dir1 pack1 mod1 func1()")
dia2/pack1/mod2.py
def func2():
print("dir2 pack1 mod2 func2()")
sys.path.extend()によりdir1とdir2の両方からモジュールを検索できるように設定して、pack1からmod1とmod2をインポートします。pack1パッケージの場所はdir1とdir2で離れていてもモジュールは同じpack1に含まれているので問題ないはずですが、
test.py
import sys
sys.path.extend(["dir1", "dir2"])
from pack1 import mod1, mod2
mod1.func1()
mod2.func2()
この結果は、次のようにmod2のインポートがエラーになりうまくいきません。
Traceback (most recent call last):
File "test.py", line 3, in <module>
from pack1 import mod1, mod2
ImportError: cannot import name 'mod2' from 'pack1'
この場合、両方のpack1以下の__init__.pyファイルを削除すると、期待通りに動作します。
dir1/
┗ pack1/
┗ mod1.py
dir2/
┗ pack1/
┗ mod2.py
dir1 pack1 mod1 func1()
dir2 pack1 mod1 func2()
これは名前空間パッケージと呼ぶしくみです。__init__.pyがないので、通常のパッケージとは認識されませんが、ディレクトリ階層を名前空間としてインポートに指定できます。
名前空間パッケージは、同一名のディレクトリを一種類の名前空間として扱うことができるので、同じディレクトリ名を分散して配置したものを、まとめてインポートできる利点があります。あるいは、ディレクトリでスクリプトファイルを整理したいだけなら、名前空間パッケージが役に立ちます。