Python では、再利用可能な関数などを集めたスクリプトファイルのことをモジュールと呼びます。 さらに、同系列のモジュールを集めたものをパッケージと呼びます。
モジュールやパッケージを作成しておくと、他のファイルから import
して使用することができます。
コラム: このあたりは、Node.js も同様の命名をしています。
下記は、簡単な関数(add
と sub
)を提供する mymath
モジュールを定義する例です。
といっても、単純に関数を定義するだけです。
モジュールは、モジュール名.py というファイル名で作成する必要があります。
def add(a, b):
"""Return the sum of a and b."""
return a + b
def sub(a, b):
"""Subtract b from a."""
return a - b
上記の mymath.py
で定義されている関数を使用するには、Python 標準のモジュールと同様に、import mymath
という形でインポートします。
import mymath
if __name__ == '__main__':
print(mymath.add(1, 2))
print(mymath.sub(1, 2))
モジュール (*.py
) をディレクトリにまとめたものを パッケージ と呼びます。
下記の例では、mylib
ディレクトリに mymath.py
を格納することで、mylib
パッケージを作成しています。
ちなみに、パッケージ名(ディレクトリ名)にはアンダースコア (_
) は含んではいけません。このあたりの詳細は Python のコーディングスタイル を参照してください。
+-- main.py
+-- mylib/
+-- mymath.py
パッケージ内のモジュールは、通常のモジュールと同様にコーディングします。
def add(a, b): return a + b
def sub(a, b): return a - b
mylib
パッケージ内のモジュールを使用するには、下記のように mylib.mymath
という形でインポートします。
import mylib.mymath
if __name__ == '__main__':
print(mylib.mymath.add(1, 2))
print(mylib.mymath.sub(1, 2))
毎回 mylib
というプレフィックスをつけてアクセスするのが面倒な場合は、from mylib import mymath
という形でインポートします。
from mylib import mymath
if __name__ == '__main__':
print(mymath.add(1, 2))
print(mymath.sub(1, 2))
このようなディレクトリ構成で libs
パッケージを作っていて、mod1.py
から mod2.py
をインポートしたいときは、次のように from .
を付けて相対パスでの参照であることを明示する必要があります。
from . import mod2
def hello():
mod2.hello()
def hello():
print('hello')
上記の from . import mod2
となっているところを、単純に import mod2
と書いてしまうと、main.py
から次のように mod1
経由で読み込もうとしたときに ModuleNotFoundError: No module named 'mod2'
エラーになってしまいます。
from libs import mod1
mod1.hello()
ちなみに、1 つ上の階層にあるモジュールをインポートしたいときは、ドットの数を 1 つ増やして ..
とします。
2 つ上の階層のモジュールをインポートしたければ、さらにドットを増やして ...
です。
まとめておきます。
from . import mod
/ from .mod import hello
from .. import mod
/ from ..mod import hello
from ... import mod
/ from ...mod import hello
パッケージ名やモジュール名が長すぎて扱いにくい場合や、名前の衝突が起きてしまう場合は、as
キーワードを使って別名を付けることができます。
import longlongmodule as libs
libs.hello()
from mypackage import longlongmodule as libs
libs.hello()
import mymodule
とすると、下記の順で mymodule.py
が検索され、最初に見つかったモジュールがインポートされます。
mymodule
sys.path
に登録されているディレクトリ内の mymodule.py
(デフォルトでは下記のディレクトリが登録されます)
同じディレクトリにあるモジュールよりも、ビルトイン・モジュールが先に検索されるところがポイントですね。 このような優先順位になっていることで、ユーザモジュールによって既存プログラムの動作が破壊されることを防いでいます。
Python 3.3 より前のバージョンでは、パッケージディレクトリに __init__.py
というファイルを置かなければ、そのディレクトリをパッケージとして認識させることができませんでした(ImportError: No module named ...
というエラーが発生する)。
Python 3.3 以降では単純にディレクトリ内に .py ファイルを放り込んでおけば、そのディレクトリをパッケージとして扱うことができるようになっています(詳細は PEP 420 – Implicit Namespace Packages を参照)。
パッケージディレクトリに置かれた __init__.py
は、そのパッケージ(あるいはその中のモジュール)をインポートしたときに実行されます。
例えば、__init__.py
の中で各モジュールをインポートするように記述しておけば、パッケージを利用するときに個々のモジュールを指定してインポートする必要がなくなります(ただし、必要のないモジュールまでデフォルトでインポートしてしまうのは効率が悪いので、オススメはできません)。
+-- main.py
+-- mylib/ (パッケージ)
+-- __init__.py
+-- mymod1.py (モジュール)
+-- mymod2.py (モジュール)
from . import mymod1
from . import mymod2
import mylib # これだけで mylib.mymod1 と mylib.mymod2 がインポートされる
if __name__ == '__main__':
mylib.mymod1.foo()
mylib.mymod2.bar()
例えば、下記のような2つのサブパッケージを含むパッケージ mylib
があったとします。
+-- mylib/
+-- sub1/
| +-- mod1.py
+-- sub2/
+-- mod2.py
sub2/mod2.py
の中から、sub1/mod1.py
をインポートするには下記のように記述します。
from ..sub1 import mod1
mod1.hello()
パッケージを指定するときに、ドットを2つ付けることで上位階層のパッケージを参照することを示しています。
モジュールの先頭に """..."""
という形式のドキュメンテーションコメントを記述しておくと、そのモジュールのドキュメントして認識されます。
"""Fibonacci numbers module."""
def fib(n):
"""Print fibonacci series up to n."""
a, b = 0, 1
while b < n:
print(b, end=' ')
a, b = b, a+b
このように記述したドキュメントは、pydoc
コマンドなどで参照することができます。
$ 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
の先頭にドキュメンテーションコメントを記述します。
"""My first package."""
パッケージのドキュメントを参照すると、パッケージに含まれているモジュールのリスト (PACKAGE CONTENTS
) も表示してくれます。
$ pydoc mylib
Help on package mylib:
NAME
mylib - My first package.
PACKAGE CONTENTS
mymod1
mymod2
パッケージ内の個々のモジュールのドキュメントを参照したい場合は、pydoc mylib.mymod1
のように、パッケージ名の後ろにドットで繋げてモジュールを指定すれば OK です。