🎃

モジュール、パッケージ、ライブラリ。python3の場合

2024/03/17に公開

python3では、モジュール、パッケージ、ライブラリがそれぞれ用語として登場する。

モジュール

用語集には次のように書いてある。

https://docs.python.org/ja/3/glossary.html#term-module

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 していることがわかる。

https://github.com/python/cpython/blob/3.11/Lib/os.py#L52-L81

ライブラリ

なんと用語集に記述がない。
doc.python.org から"ライブラリ"で検索すると、python3本体と同時に配布されてるモジュール群にたどり着く。
これらは機構的にはモジュールと区別はつかない。

公式ドキュメントに一覧がある通りではある。

https://docs.python.org/ja/3/library/index.html

より具体的には python3 のソースの Lib ディレクトリの中身がそうだとは言える。かもしれない。

https://github.com/python/cpython/tree/3.11/Lib

いずれも lib という名前を冠しており、明確である。

linuxでは、概ね次のようなディレクトリに格納されている。

/usr/lib/python$VERSION/

例えば collections モジュールは次のディレクトリにある。

/usr/lib/python3.10/collections

パッケージ

一応、用語集に定義があるにはある。

https://docs.python.org/ja/3/glossary.html

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 116 22:51 __init__.py
-rw-r--r--  1 root root 1198 116 22:51 __main__.py
-rw-r--r--  1 root root 1444 116 22:51 __pip-runner__.py
drwxr-xr-x  2 root root 4096 1124 17:31 __pycache__
drwxr-xr-x 16 root root 4096 1124 17:31 _internal
drwxr-xr-x 24 root root 4096 1124 17:31 _vendor
-rw-r--r--  1 root root  286 116 22:51 py.typed

/usr/lib/python3.10/site-packages/pip-22.3.1.dist-info:
合計 76
-rw-r--r-- 1 root root  1093 116 22:51 LICENSE.txt
-rw-r--r-- 1 root root  4072 116 22:51 METADATA
-rw-r--r-- 1 root root 55829 116 22:51 RECORD
-rw-r--r-- 1 root root    92 116 22:51 WHEEL
-rw-r--r-- 1 root root   125 116 22:51 entry_points.txt
-rw-r--r-- 1 root root     4 116 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