モジュール、パッケージ、ライブラリ。python3の場合
python3では、モジュール、パッケージ、ライブラリがそれぞれ用語として登場する。
モジュール
用語集には次のように書いてある。
Python コードの組織単位としてはたらくオブジェクトです。モジュールは任意の Python オブジェクトを含む名前空間を持ちます。モジュールは importing の処理によって Python に読み込まれます。
一般的には、import で読み込めるファイル群 と言うべきか。<それって小生の感想ですよ>
例えば単に
import hogehoge
とすると、
- hogehoge.py
- hogehoge/__init__.py
どちらかを読み込む可能性がある。
(より厳密には、さらにこれらを sys.path から探す )
初学者を混乱させることがこの多い機能だが、実は便利なこともある。
最初は単一ファイルで設計しておき、複雑になってきてから、ディレクトリを掘って分割すれば良い。しかも呼び出す側からはその点について考慮する必要はないと考えることもできる。
コードの組織単位としてはたらくオブジェクトです
前述の用語集で「オブジェクトです」と言っていたことを思い出してほしい。
importが成功したモジュールは、moduleのインスタンスとなることを示している。
moduleインスタンスを、pythonのスクリプト側から直接作る手段はない。内部的なオブジェクトである。
$ python3
Python 3.10.8 (main, Nov 1 2022, 14:18:21) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import collections
>>> collections
<module 'collections' from '/usr/lib/python3.10/collections/__init__.py'>
>>>
__init__.py を読み込んでいることもわかるだろう。
もう少し例をあげる。
import osで、小生の archlinux の環境では次のようになる。
os.pathも付随しているのがわかる。
$ python3
Python 3.10.9 (main, Dec 19 2022, 17:35:49) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os
<module 'os' from '/usr/lib/python3.10/os.py'>
>>> os.path
<module 'posixpath' from '/usr/lib/python3.10/posixpath.py'>
厳密には os.path の読み込みには、os.py内部で posix/windows系でそれぞれモジュール実体をさらに import していることがわかる。
ライブラリ
なんと用語集に記述がない。
doc.python.org から"ライブラリ"で検索すると、python3本体と同時に配布されてるモジュール群にたどり着く。
これらは機構的にはモジュールと区別はつかない。
公式ドキュメントに一覧がある通りではある。
より具体的には python3 のソースの Lib ディレクトリの中身がそうだとは言える。かもしれない。
いずれも lib という名前を冠しており、明確である。
linuxでは、概ね次のようなディレクトリに格納されている。
/usr/lib/python$VERSION/
例えば collections モジュールは次のディレクトリにある。
/usr/lib/python3.10/collections
パッケージ
一応、用語集に定義があるにはある。
A Python module which can contain submodules or recursively, subpackages. Technically, a package is a Python module with a __path__ attribute.
小生として、期待とちょっと違う内容が書いてあって困っている。雑に訳すと「サブモジュールとサブパッケージを再起的に含むモジュール。」となるが、"パッケージ"の定義が再帰してるし、それだけなわけがないだろう。
運用面から定義するなら、
python3本体とは無関係に、 pip によって個別に更新できるモジュール群
と解釈するのが話が良さそうだ。<それって小生の感想ですよ>
より具体的には pip を体験してみてほしい。
例えば小生の環境では pip list を実行すると次のようになる。
$ pip list
Package Version
---------------------------- -----------
....
中略
....
pip 22.3.1
....
中略
....
パッケージ名らしきものと、そのバージョンが管理されていることがわかるだろう。
この一覧に、標準ライブラリが含まれていないことに着眼してほしい。
さらにインストール状態も標準ライブラリとはことなる。上で抜粋した pip モジュールだが、小生の環境では次のようになっている。
$ ls -l /usr/lib/python3.10/site-packages/pip*
/usr/lib/python3.10/site-packages/pip:
合計 28
-rw-r--r-- 1 root root 357 11月 6 22:51 __init__.py
-rw-r--r-- 1 root root 1198 11月 6 22:51 __main__.py
-rw-r--r-- 1 root root 1444 11月 6 22:51 __pip-runner__.py
drwxr-xr-x 2 root root 4096 11月 24 17:31 __pycache__
drwxr-xr-x 16 root root 4096 11月 24 17:31 _internal
drwxr-xr-x 24 root root 4096 11月 24 17:31 _vendor
-rw-r--r-- 1 root root 286 11月 6 22:51 py.typed
/usr/lib/python3.10/site-packages/pip-22.3.1.dist-info:
合計 76
-rw-r--r-- 1 root root 1093 11月 6 22:51 LICENSE.txt
-rw-r--r-- 1 root root 4072 11月 6 22:51 METADATA
-rw-r--r-- 1 root root 55829 11月 6 22:51 RECORD
-rw-r--r-- 1 root root 92 11月 6 22:51 WHEEL
-rw-r--r-- 1 root root 125 11月 6 22:51 entry_points.txt
-rw-r--r-- 1 root root 4 11月 6 22:51 top_level.txt
site-packages ディレイクトリに入れることで、ライブラリとは明確に区別しつつ、
- site-packages/pip/ にはモジュール本体が、
- site-packages/pip-22.3.1.dist-info/ に、パッケージ管理情報が
保存されていることがわかる。
故に、前述した「雑な表現」に含めて、
- python3本体とは無関係に、 pip によって個別に更新できるモジュール群
- モジュール + *.dist-info/ で管理されてるのがパッケージ
であるとも解釈できる。<それって小生の感想ですよ>
包含関係では、パッケージの方が上位と言える。
sys.path
前述の通り、ライブラリとパッケージは別のディレクトリに格納されるが、モジュール検索通路にそれらが含まれているため問題なく import できる。
archlinuxでの例を示す。
$ python3
Python 3.10.9 (main, Dec 19 2022, 17:35:49) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/usr/lib/python3.10/site-packages']
>>>
ちなみに、環境変数 PYTHONPATH を指定すると、sys.pathの先頭に追加される。
$ PYTHONPATH=/ python3
Python 3.10.9 (main, Dec 19 2022, 17:35:49) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/usr/lib/python3.10/site-packages']
>>>
Discussion