概要(Pythonのパッケージ構造は「関連機能を階層で整理する入れ物」)
Pythonのパッケージは、関連する複数のモジュール(.pyファイル)をディレクトリ階層でまとめ、再利用性と保守性を高める仕組みです。基本は「パッケージ=ディレクトリ」「モジュール=ファイル」で、階層の要点はエントリ(init.py)とインポートのルール(絶対・相対)を正しく押さえることです。初心者は「構造の型」「インポートの型」「実行コンテキスト(name)」の3点を理解すると一気に迷いが減ります。
用語と最小構造(モジュール・パッケージ・ライブラリ)
用語の整理(まず何が何かを掴む)
- モジュールは1つのPythonファイル(例: math_utils.py)。
- パッケージは複数モジュールを含むディレクトリ(サブパッケージを持てる)。
- ライブラリはパッケージやモジュールの集合(例: pandas)。
この区別が分かると「どこに置いて」「どうインポートするか」が明快になります。
最小のパッケージ構造(実例)
mypackage/
__init__.py
math_utils.py
string_utils.py
database/
__init__.py
connection.py
このように、ルートとサブパッケージに init.py を置くと階層全体をパッケージとして認識でき、ドット記法で階層的にインポートできます。
init.py とインポートの型(絶対・相対、公開制御)
init.py の役割と公開制御
init.py は「このディレクトリはパッケージ」という印です。空でもよく、初期化処理や公開対象(all)の定義を置けます。all を使うと from package import * の公開範囲を明示でき、無秩序なAPI露出を防げます。
絶対インポート(推奨)と相対インポート(同階層用)
- 絶対インポート例: from mypackage.database import connection
- 相対インポート例(同パッケージ内): from .database import connection
大半の現場で「絶対インポートが基本」。相対は「同梱の近所モジュール」を指すときに限定的に使うと混乱が減ります。
インポート例(分かりやすい型)
# 絶対インポート(推奨)
from mypackage.math_utils import add
from mypackage.database.connection import connect_db
# 相対インポート(パッケージ内の近所参照)
from .string_utils import slugify
from .database import connection
Python実行コンテキスト(name)とエントリポイント
name の意味(直接実行とimportの区別)
ファイルが直接実行されたとき name は “main“、importされたときは「パッケージ名.モジュール名」になります。エントリコード(CLIやデモ)を if name == “main“: に置くと、インポート時には動かず安全です。
# mypackage/math_utils.py
def add(a, b):
return a + b
if __name__ == "__main__":
# 直接実行時だけ走る
print(add(2, 3))
Python実践的なパッケージ設計(API面を整える)
パブリックAPIの整え方(上位から読みやすく)
「利用者がどの入口から何を使うべきか」を init.py で再公開すると、ドット記法が短くなり使いやすくなります。内部構造は変えても公開面は安定させるのがコツです。
# mypackage/__init__.py
from .math_utils import add, sub
from .string_utils import slugify
__all__ = ["add", "sub", "slugify"]
Pythonこうすると利用側は:
from mypackage import add, slugify
Pythonと短く書けます。内部の入れ替えに強く、依存面がすっきりします。
サブパッケージの分離(責務ごとに区切る)
I/O、ドメインロジック、データアクセスなどの責務ごとにサブパッケージ化すると、変更の影響範囲が限定され、保守性が向上します。命名も「何が入っているか」を即想像できる言葉にします。
例題(最小パッケージを作って使う)
例題1:最小パッケージの作成とインポート
myapp/
mypackage/
__init__.py
math_utils.py
string_utils.py
main.py
# mypackage/math_utils.py
def add(a: int, b: int) -> int:
return a + b
Python# mypackage/string_utils.py
def slugify(s: str) -> str:
return s.lower().replace(" ", "-")
Python# mypackage/__init__.py
from .math_utils import add
from .string_utils import slugify
__all__ = ["add", "slugify"]
Python# main.py
from mypackage import add, slugify
print(add(3, 5)) # 8
print(slugify("Hello World")) # hello-world
Pythonこの構造と使い方は「入口が整理された使いやすいAPI」を作る基本型です。
例題2:サブパッケージと絶対インポート
mypackage/
__init__.py
database/
__init__.py
connection.py
service/
__init__.py
user.py
# mypackage/database/connection.py
def connect_db(url: str):
return f"connect to {url}"
Python# mypackage/service/user.py
from mypackage.database.connection import connect_db
def get_user(uid: str):
conn = connect_db("sqlite:///local.db")
return {"id": uid, "conn": conn}
Python絶対インポートで階層が明確になり、可読性・検索性が高まります。
よくあるつまずきと解決(入口・パス・構造の勘所)
「直接実行でインポートが壊れる」問題
パッケージ内のモジュールを直接 python file.py で実行すると、相対インポートが失敗しがちです。パッケージのルートで python -m mypackage.module の形を使うか、エントリポイントをプロジェクト直下(main.py や CLI)に置いて実行する設計にします。
相対インポートの連鎖で迷子になる
相対を多用すると、構造変更で壊れやすくなります。基本は絶対インポートに寄せて、相対は「同階層の最小範囲」で限定的に使う運用へ。
init.py を忘れてパッケージ扱いにならない
ディレクトリをパッケージとして認識させるために init.py を置きます。空で十分ですが、公開APIや初期化をここへまとめると運用が楽になります。
まとめ(階層・入口・インポートの型を覚える)
パッケージ構造の核心は「階層で責務を分ける」「init.pyで入口を整える」「絶対インポートを基本にする」「nameで実行とimportを分ける」の4点です。これらを型として統一すれば、初心者でも短い構成で「見通しが良く、壊れにくく、再利用しやすい」パッケージを作れます。定義と構造例、インポート指針は上記のとおりで、迷ったら「絶対インポート+公開APIの再輸出」を選ぶと安定します。
