この記事のポイント

  • init.py設計の暗黙的な依存肥大を読み解く力が身につく
  • サブパッケージ構造をレビュー視点で整理できる
  • モジュール境界・責務分離・公開API設計を体系化できる
  • 実務レビューで設計臭を検出する技法を学べる

そもそも__init__.pyとは

Pythonにおける__init__.pyは、パッケージ認識・初期化制御・エクスポート整理という3つの役割を持つファイルです。

  • ディレクトリがパッケージと認識される(Python3.3以降は暗黙的だが依然慣例として残る)
  • サブモジュールの初期化処理(副作用コード含む)が実行可能
  • サブモジュール・クラス・関数をエクスポート整理
典型的__init__.py使用例
# services/__init__.py

from .user_service import UserService
from .order_service import OrderService

__all__ = ["UserService", "OrderService"]

これにより、呼び出し側では以下のように書けます。

from services import UserService

なぜこれをレビューするのか

init.pyは便利すぎる反面、設計崩壊の入口になりやすい領域です。レビューアーは以下のような依存設計の歪みを読み解く責任があります。

レビューアー視点

  • init.py肥大化による循環依存リスクを検出する
  • エクスポート範囲の適切性を確認する
  • パッケージ境界の責務分離が破綻していないか確認する
  • 内部実装と公開APIの整理状況を読む
  • 再帰的インポートが隠れていないか確認する

開発者視点

  • from-importが楽で__init__.pyに次々追加してしまう
  • API公開意識が希薄なまま「全部import」になりやすい
  • 循環importのエラーが出てから慌てて整理を始める
  • テスト実行時に副作用実行が発生して気づく

init.py設計が崩壊する構造

init.py肥大化の典型症状
  • サブモジュール全てをimportして束ねるだけの巨大エクスポーター化
  • 実行時初期化コードが__init__.pyに混入
  • 順序依存importが生じ循環依存を誘発
  • どのモジュールが利用可能なのか可視性が消失
  • 境界責務が不明瞭になる

実際の崩壊コードを例示します。

肥大化__init__.py
# services/__init__.py

from .user_service import UserService, create_user, delete_user
from .order_service import OrderService, create_order, cancel_order
from .payment_service import PaymentService, process_payment

__all__ = [
    "UserService", "create_user", "delete_user",
    "OrderService", "create_order", "cancel_order",
    "PaymentService", "process_payment"
]
@Reviewer
全モジュール統合が続いており依存膨張が進行中です。公開API層を分離しましょう。

init.py崩壊の依存構造モデル

UML Diagram

良い実装例:公開API層分離

設計肥大を防ぐには「エクスポート層(facade)と内部層を分離」が有効です。

ディレクトリ構造

services/
  __init__.py
  api.py
  user_service.py
  order_service.py
  payment_service.py
__init__.pyを薄く保つ
# services/__init__.py

from .api import *
api.pyに公開API集中
# services/api.py

from .user_service import UserService, create_user, delete_user
from .order_service import OrderService, create_order, cancel_order
from .payment_service import PaymentService, process_payment

__all__ = [
    "UserService", "create_user", "delete_user",
    "OrderService", "create_order", "cancel_order",
    "PaymentService", "process_payment"
]

改善ポイント

  • init.pyは完全に薄く保持
  • 公開APIをapi.pyで集中管理
  • 内部依存を隠蔽可能
  • 循環依存発生確率が劇的低下
レビュー文化は「init.pyを薄く保て」で統一すると崩壊防止力が高まります。

良くない実装例: ケース1(副作用混入)

__init__.pyに副作用
# services/__init__.py

from .user_service import UserService

# グローバル初期化副作用
UserService.initialize_global_connection()
@Reviewer
__init__.pyに副作用処理が混入しています。import時副作用は避け、明示実行に分離してください。

問題点

  • テスト時に想定外初期化が発生
  • 依存先の初期化順序制御が困難化

良くない実装例: ケース2(import漏れ誘発)

エクスポート漏れリスク
# services/__init__.py

from .user_service import UserService

# order_serviceのimport忘れ発生
@Reviewer
API公開管理が散在し、import漏れの温床になります。集中公開層を導入してください。

問題点

  • API追加時に複数ファイルの変更作業が必要になる
  • import漏れがレビューで検出しづらい

改善例:責務整理型設計

集中API層版

# services/api.py

from .user_service import UserService
from .order_service import OrderService
from .payment_service import PaymentService

__all__ = [
    "UserService",
    "OrderService",
    "PaymentService",
]

PlantUML:責務整理構造イメージ

UML Diagram

観点チェックリスト

まとめ

init.pyは便利な道具ですが「便利すぎる設計臭の源泉」にもなりやすい領域です。レビューアーは「パッケージの入口構造を制御できているか?」という視点を常に持ち続けることが、Python設計レビュー文化の中核になります。