Python でパッケージを配布するには、ディレクトリを「パッケージ」として認識させる必要がある。従来、この役割を担っていたのが __init__.py ファイル。
Python 3.3 以降では「名前空間パッケージ」の導入により、__init__.py がなくてもパッケージとして認識されるようになった。しかし配布パッケージを作成する場合は、今でも __init__.py を置くのが標準的なやり方となっている。
my_package/
__init__.py
module_a.py
module_b.py
subpackage/
__init__.py
module_c.py
上の構造では、my_package と subpackage の両方に __init__.py を置いている。このファイルは空でもかまわないが、パッケージの初期化コードや公開 API の定義に使うことが多い。
init.py が必要な理由
配布パッケージで __init__.py を使う理由はいくつかある。
__init__.py があることで、そのディレクトリが意図的にパッケージとして設計されていることが明確になる。ビルドツールやインストーラがパッケージを正しく認識するために重要だ。
パッケージがインポートされたときに実行したいコードを __init__.py に書ける。ロギングの設定やサブモジュールの事前読み込みなどに使う。
__all__ 変数を定義して、from package import * で公開するモジュールや関数を制御できる。
たとえば __init__.py で公開 API を定義するには、次のように書く。
# my_package/__init__.py
from .module_a import useful_function
from .module_b import AnotherClass
__all__ = ['useful_function', 'AnotherClass']
こうしておくと、利用者は from my_package import useful_function のように簡潔にインポートできる。
pyproject.toml との関係
現在の Python パッケージングでは pyproject.toml が設定ファイルの標準となっている。setuptools を使う場合、パッケージの自動検出機能がディレクトリ内の __init__.py を探してパッケージを認識する。
[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "my_package" version = "0.1.0"
setuptools.discovery はデフォルトで __init__.py を含むディレクトリをパッケージとして扱う。__init__.py がないディレクトリは、明示的に設定しない限りパッケージに含まれない。
配布を前提としたパッケージでは、すべてのパッケージディレクトリに __init__.py を置くのが確実。