跳至主要内容

Python __init__ 檔

什麼是 __init__.py

在 Python 中,__init__.py 是一個特殊檔案,其存在讓一個目錄被 Python 識別為 package(套件),而不只是普通資料夾。

作用

當你的目錄結構如下:

myproject/
├── __init__.py
└── utils.py

Python 便可以用 import myproject.utils 的方式載入模組。

若沒有 __init__.py,Python 3.3+ 雖支援 namespace packages(隱式套件),但仍建議明確加入此檔案以確保相容性與可讀性。

常見用途

  • 空白檔案:僅標記目錄為 package
  • 初始化邏輯import 套件時自動執行的程式碼
  • 公開 API:透過 __all__ 控制對外暴露的介面
# myproject/__init__.py
from .utils import helper_function
__all__ = ["helper_function"]

這樣使用者只需 from myproject import helper_function 即可取用。

具體應用場景

1. 簡化 import 路徑

不用讓使用者記住內部模組結構,透過 __init__.py 重新匯出,提供乾淨的公開介面。

# mylib/
# ├── __init__.py
# ├── _parser.py
# └── _validator.py

# mylib/__init__.py
from ._parser import parse
from ._validator import validate

使用者可以直接寫:

from mylib import parse, validate
# 而不是 from mylib._parser import parse

2. 套件版本管理

將版本號集中定義在 __init__.py,方便工具(如 setuptools)和使用者讀取。

# mylib/__init__.py
__version__ = "1.2.0"
__author__ = "Your Name"

其他地方讀取:

import mylib
print(mylib.__version__) # "1.2.0"

3. 自動註冊子模組(Plugin 系統)

框架常用此模式,讓子目錄的 plugin 在 import 時自動完成註冊。

# plugins/__init__.py
from . import csv_plugin, json_plugin, excel_plugin

只要 import plugins,三個 plugin 全部載入並完成初始化,不需逐一手動引入。


4. 環境初始化(logging、設定)

進入套件時統一設定 logging 格式或讀取環境變數,避免分散在各模組重複設定。

# myapp/__init__.py
import logging

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
)

5. 條件式匯入(相容性處理)

根據執行環境決定載入哪個實作,常見於需要同時支援不同平台或依賴的套件。

# mylib/__init__.py
try:
from ._fast import compute # C extension 加速版
except ImportError:
from ._pure import compute # 純 Python 備援版

使用者直接 from mylib import compute,無需感知底層差異。

什麼時候不該用 __init__.py

1. __init__.py 塞太多邏輯

__init__.py 應該是「入口」,不是「倉庫」。若把大量業務邏輯、類別定義直接寫在裡面,會讓套件難以維護。

# 不建議:把所有東西塞進 __init__.py
class UserService:
...

class PaymentService:
...

def send_email():
...

應拆分到各自模組,再從 __init__.py 重新匯出。


2. 製造循環 import

__init__.py 在套件載入時最先執行,若它 import 了某模組,而該模組又 import 回套件本身,就會造成循環依賴錯誤。

# mylib/__init__.py
from .models import User # models.py 若又 import mylib,就會出錯

遇到此情況,應改為在函式內部做 lazy import,或重新整理模組依賴關係。


3. 大型 namespace package 不需要它

若你在維護一個跨多個發行套件共用同一頂層命名空間(如 mycompany.billingmycompany.auth 分屬不同 repo),刻意不放 __init__.py 才能讓 Python 的 namespace package 機制正確合併它們。

加了反而會破壞其他套件對同一命名空間的存取。


4. 單一檔案就夠用時

若你的程式碼只有一個 utils.py,直接 import utils 即可,完全不需要建立資料夾 + __init__.py 的結構。過早建立套件結構只會增加複雜度。