Python | Web / API:Python のパッケージ構造

Python Python
スポンサーリンク

概要(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の再輸出」を選ぶと安定します。

タイトルとURLをコピーしました