0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pythonの__init__.pyってなんなのか?

Last updated at Posted at 2025-04-21

Pythonでパッケージを作成・管理する際,必ず目にするファイルが__init__.pyである.みなさんは__init__.pyって何かわかりますか?FlaskとかDjangoとかで何となく出てくるので脳死で使っている人も多いのではないでしょうか?

私もあまりわからず使っていました!

__init__.pyを知る前に...まずはPythonのimport処理とsys.pathによるモジュール検索の仕組み知る必要があります!そこから説明します!

1. importとsys.pathの仕組み

1.1 Pythonインタプリタとは

  • ソースコードを読み込み,字句解析→構文解析→バイトコード生成→実行までを担うプログラム
  • import文を遇うとモジュール検索と読み込みを開始する

モジュールとは?

  • Pythonの“モジュール”は,関数・クラス・変数などをまとめたコードの部品
  • 原則として1ファイル(.py)が1モジュール
  • モジュールは名前空間 (namespace) を提供し,衝突を防ぐ
  • 別ファイルやREPLからimport モジュール名で再利用可能

REPLとは,Read-Eval-Print Loopの略で,Pythonの対話型実行環境のこと

1.2 sys.pathの役割

sys.pathはPythonインタプリタがモジュールやパッケージを探すパスのリストである.
主な内容:

  1. 標準ライブラリのインストールディレクトリ
  2. 実行中スクリプトの所在ディレクトリ
  3. PYTHONPATH環境変数で追加されたディレクトリ

PYTHONPATHとは?
環境変数の一つで,Pythonがモジュールを検索する際に参照するパスのリスト.
PYTHONPATHに指定されたディレクトリは,sys.pathの先頭に追加される.

インタプリタはsys.pathを先頭から順に調べ,対象の名前に対応する

  • <name>.py モジュール
  • <name> ディレクトリ(中に__init__.pyがある場合)
    を探す.

文章で説明してもわかりにくいと思うのであるので,実際にsys.pathを確認してみましょう.

以下のディレクトリ構造のPythonプロジェクトを考えます.

my_project/
├── main.py
├── my_package/
│   ├── __init__.py
│   ├── sub_a.py
│   └── sub_b.py
└── my_module.py

sys.pathを確認するために,以下のようなコードを書いてみましょう.

main.py
import sys, pprint
import my_package          # ここで実際にインポート
print('--- sys.path ---')
pprint.pprint(sys.path)
print('--- loaded modules ---')
pprint.pprint([m for m in sys.modules if m.startswith('my_package')])

このコードをmain.pyに書いて実行すると,以下のような出力が得られる.

python3 main.py
--- sys.path ---
['/Users/.../my_project', ...]
--- loaded modules ---
['my_package', 'my_package.sub_a', 'my_package.sub_b']

つまり,sys.path は

  • “モジュールそのもの” ではなく
  • “モジュールを探しに行くディレクトリのリスト”
    を保持しているだけ
    Python はこのリストに載っているディレクトリの中を順番に探し,
  1. 指定されたモジュール名.py
  2. 指定されたモジュール名という名前の パッケージ(=その名前のディレクトリ+ __init__.py
    のどちらかを見つけた時点で読み込む.

したがって

my_project/          ← このディレクトリが sys.path に入る
├── main.py
├── my_package/      ← ここは「探す対象」であって sys.path には入らない
│   ├── __init__.py
│   ├── sub_a.py
│   └── sub_b.py
└── my_module.py

という構成で python3 main.py を実行すると

/Users/.../my_project   ← #0  ← スクリプトが置かれているディレクトリ
...

のように my_project だけが sys.path に入り,その中にある my_package は入らない.
でも import my_package は問題なく成功しますよね??

理由は,Python が sys.path[0](今回なら /Users/.../my_project)を開く
その直下に my_package という名前の ディレクトリ+__init__.py があるか調べる
という手順で検索するからです。

よくある勘違い

  • 「パッケージが sys.path に入っていないと import 出来ない」
    → ルートディレクトリが入っていれば OK
  • sys.path.append('.../my_project/my_package') しないとダメ?
    → 不要。逆にやると import my_package.sub_a が壊れる場合がある

2. init.pyとは何か

それでは__init__.pyの色々を堀探ってみましょう.

2.1 パッケージ認識と初期化

  • ディレクトリに__init__.pyがあると「このフォルダはパッケージ」とPythonが認識
  • インポート時に一度だけ__init__.pyを実行し,初期化処理(ログ設定や共通変数定義など)を行う

2.2 歴史的経緯と役割

  1. Python 2系では必須ファイル
  2. Python 3.3以降はPEP 420で名前空間パッケージも可能になったが,明示的な初期化処理やAPI公開制御のために__init__.pyが今も有用
  3. サブモジュールのまとめ読み込みや外部公開APIの制御にも使える

2.3 init.pyに書けること

  • 空ファイルでもパッケージとして機能
  • 初期化処理を記述して,import時に一度だけ実行
  • __all__ を定義して公開APIを制御
  • サブモジュールをまとめてimportさせるエイリアスを作成

例えば以下のようにかける

my_package/__init__.py
import logging  
logging.basicConfig(level=logging.INFO)

__all__ = ['sub_a', 'sub_b']  
from .sub_a import ClassA  
from .sub_b import function_b

2.4 相対インポートで構造化

同一パッケージ内のモジュールを相対パスでimportすると,名前衝突を避けられる

from .sub_a import ClassA       # 同階層  
from ..parent.sub_c import helper  # 上位階層  

3. Flaskプロジェクトでの__init__.pyの役割

3.1 エントリーポイントとしての位置付け

Flaskでは環境変数FLASK_APPにパッケージ名を指定すると,そのパッケージの__init__.pyが最初に読み込まれる.ここにアプリ生成関数を定義すると,設定・拡張機能・Blueprintの初期化を一元管理できる.

3.2 create_app関数で起動処理をまとめる

my_flask_app/__init__.py
from flask import Flask  
from .config import Config  
from .extensions import db, migrate  
from .blueprints import main_bp  

def create_app():  
    app = Flask(__name__)  
    app.config.from_object(Config)  
    db.init_app(app)  
    migrate.init_app(app, db)  
    app.register_blueprint(main_bp)  
    return app  

4. ダンダー(double underscore)属性の特別扱い

4.1 命名規則と種類

前後にアンダースコア2つを付けた名前をダンダー(double underscore)属性と呼ばれ,Pythonのデータモデルに組み込まれている.
代表例は以下の6つ:

  • __init__
  • __name__
  • __repr__
  • __len__
  • __enter__
  • __exit__

4.2 Pythonインタプリタ内部での自動検出・呼び出しの使用例

  1. __init____repr__ の例
class MyClass:
   def __init__(self, x):
       self.x = x               # インスタンス生成時に呼ばれる
   def __repr__(self):
       return f"MyClass(x={self.x})"  # repr() や print() で使われる

obj = MyClass(10)
print(obj)       # -> MyClass(x=10)
  1. __len__ の例
class MyCollection:
    def __init__(self, items):
        self.items = list(items)
    def __len__(self):
        return len(self.items)  # len() で返り値になる

col = MyCollection([1,2,3,4])
print(len(col))  # -> 4
  1. __enter____exit__の例
class Resource:
    def __enter__(self):
        print("Enter")
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exit")

with Resource() as r:
    print("using resource")
# -> Enter
#    using resource
#    Exit
  1. **__name__ の例
def main():
    print("This is main")

if __name__ == "__main__":
    main()  # スクリプトとして実行されたときだけ呼び出される

これらのダンダー(double underscore)属性はPythonインタプリタが内部で自動的に検出・呼び出す仕組みを持っており,ユーザーコードは定義するだけでよい.


このように__init__.pyはPythonのモジュールシステムにおいて重要な役割を果たしていることがわかる.
__init__.pyを理解することで,Pythonのモジュールやパッケージの仕組みをより深く理解できるようになるでしょう!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?