モジュールとパッケージ
Python では、再利用可能な関数などを集めたスクリプトファイルのことをモジュールと呼びます。 さらに、同系列のモジュールを集めたものをパッケージと呼びます。
- モジュール … 再利用可能なスクリプト (.py)
- パッケージ … 上記のモジュールをディレクトリに集めたもの
モジュールやパッケージを作成しておくと、他のファイルから import
して使用することができます。
.js
ファイルのことをモジュール、それらをまとめたものをパッケージと読んでいます。モジュールを作成する
下記は、簡単な関数(add
と sub
)を提供する mymath
モジュールを定義する例です。
といっても、単純に関数を定義するだけです。
モジュールは、モジュール名.py
というファイル名で作成する必要があります。
上記の mymath.py
で定義されている関数を使用するには、Python 標準のモジュールと同様に、import mymath
という形でインポートします。
パッケージを作成する
複数のモジュール (*.py
) をディレクトリにまとめたものを パッケージ と呼びます。
下記の例では、mylib
ディレクトリに mymath.py
を格納することで、mylib
パッケージを作成しています。
ちなみに、パッケージ名(ディレクトリ名)には、アンダースコア (_
) は含めるべきではない とされています。
このあたりの命名規則に関しては Python のコーディングスタイル を参照してください。
+-- main.py
+-- mylib/
+-- mymath.py
パッケージ内のモジュールの実装方法は、通常のモジュールの場合と変わりません。
mylib
パッケージ内の mymath
モジュールを使用するには、次のように mylib.mymath
という形でインポートします。
このようにパッケージ名とモジュール名を繋げた名前でインポートした場合、関数を呼び出すときもその名前をプレフィックスに付けて呼び出す必要があります(例: mylib.mymath.add(1, 2)
)。
Python の部分インポート (partial import) の構文 (from mylib import mymath
) を使うと、パッケージ名を省略して呼び出せるようになります。
from mylib import mymath
if __name__ == '__main__':
print(mymath.add(1, 2))
print(mymath.sub(1, 2))
モジュール内の関数などを呼び出すときは、import
の後ろに記述したシンボル名をプレフィックスとして付けると覚えておけば OK です(例えば上記の場合は、import mymath
としているので、add
関数の呼び出し時は mymath
プレフィックスを付けて mymath.add
とします)。
モジュール内の特定メンバーだけをインポートする
前述の例では、モジュール単位でインポートしましたが、モジュール内の特定のメンバー(関数、クラス、定数など)を指定してインポートすることもできます。
次の例では、mymath
モジュール内の、add
関数のみをインポートしています。
関数の呼び出し時に、モジュール名のプレフィックスを付ける必要はありません。
パッケージ内のモジュール内の関数をインポートする場合も、ほぼ同じ指定方法でいけます。
from mylib.mymath import add
if __name__ == '__main__':
print(add(1, 2))
別名を付ける (as)
インポートするモジュールや関数の名前が長すぎて扱いにくい場合や、名前の衝突が起きてしまう場合は、as
キーワードを使って別名を付けることができます。
パッケージ内のモジュールから別のモジュールをインポートするときの注意
+-- main.py
+-- libs/
+-- mod1.py
+-- mod2.py
このようなディレクトリ構成で libs
パッケージを作っていて、mod1.py
から mod2.py
をインポートしたいときは、次のように from .
を付けて、相対パスインポート の形で記述する必要があります(逆に、ドット (.
) を使わないインポートを絶対パスインポートと呼びます)。
上記の from . import mod2
となっているところを、単純に import mod2
と書いてしまうと、main.py
から次のように mod1
経由で読み込もうとしたときに ModuleNotFoundError: No module named 'mod2'
エラーになってしまいます。
python
コマンドで何らかのスクリプト (.py
) を起動すると、そのファイルが存在するディレクトリがモジュールの検索パスに追加されます。
上記の例で言うと、main.py
と同じディレクトリにあるモジュールであれば絶対パスでインポートできるようになります。
一方で、libs/mod1.py
が処理されているときも、libs
ディレクトリは検索パスに含まれていないため、import mod2
という絶対パスインポートはエラーになってしまいます(main.py
と同じディレクトリの mod2.py
を探そうとしてしまう)。
もちろん、main.py
からの絶対パスで from libs import mod2
と記述することは可能ですが、それよりは相対パスで from . import mod2
と記述した方が分かりやすいでしょう。別の階層のモジュールをインポートする
同じパッケージ階層のモジュールをインポートするときは、相対パスで from . import モジュール名
としましたが、1 つ上の階層にあるモジュールをインポートしたいときは、ドットの数を 1 つ増やして from .. import モジュール名
とします。
2 つ上の階層のモジュールをインポートしたければ、さらにドットを増やして from ... import モジュール名
とします。
- 同じ階層のモジュール(内のメンバー)のインポートする場合
from . import mod
from .mod import hello
- 1 つ上の階層のモジュール(内のメンバー)のインポートする場合
from .. import mod
from ..mod import hello
- 2 つ上の階層のモジュール(内のメンバー)のインポートする場合
from ... import mod
from ...mod import hello
例えば、下記のような 2 つのサブパッケージを含むパッケージ mylib
があったとします。
+-- mylib/
+-- sub1/
| +-- mod1.py
+-- sub2/
+-- mod2.py
sub1/mod1.py
の中から、sub2/mod2.py
をインポートするには下記のように記述します。
パッケージの初期化ファイル (__init.py__)
Python 3.3 より前のバージョンでは、パッケージディレクトリに __init__.py
というファイルを置かなければ、そのディレクトリをパッケージとして認識させることができませんでした(ImportError: No module named ...
というエラーが発生する)。
Python 3.3 以降では単純にディレクトリ内に .py ファイルを放り込んでおけば、そのディレクトリをパッケージとして扱うことができるようになっています(詳細は PEP 420 – Implicit Namespace Packages を参照)。
パッケージディレクトリに置かれた __init__.py
は、そのパッケージ(あるいはその中のモジュール)をインポートしたときに実行されます。
例えば、__init__.py
の中で各モジュールをインポートするように記述しておけば、パッケージを利用するときに個々のモジュールを指定してインポートする必要がなくなります(ただし、必要のないモジュールまでデフォルトでインポートしてしまうのは効率が悪いので、オススメはできません)。
モジュールのドキュメンテーションコメントを記述する
モジュールの先頭に """コメント"""
という形式のドキュメンテーションコメントを記述しておくと、そのモジュールのドキュメントして認識されます。
このように記述したドキュメントは、pydoc
コマンドや help
関数などで参照することができます。
$ pydoc fibo
Help on module fibo:
NAME
fibo - Fibonacci numbers module.
FUNCTIONS
fib(n)
Print fibonacci series up to n.
FILE
D:\y\sandbox\python\fibo.py
パッケージ単位のドキュメントを記述したいときは、そのパッケージの __init__.py
の先頭にドキュメンテーションコメントを記述します。
pydoc
コマンドでパッケージドキュメントを参照すると、そのパッケージに含まれているモジュールのリスト (PACKAGE CONTENTS
) も表示してくれます。
$ pydoc mylib
Help on package mylib:
NAME
mylib - My first package.
PACKAGE CONTENTS
mymod1
mymod2
パッケージ内の個々のモジュールのドキュメントを参照したい場合は、pydoc mylib.mymod1
のように、パッケージ名の後ろにドットで繋げてモジュールを指定します。