順番に読み進めながら学べます

__init__.py と相対インポート — パッケージで複数ファイルを束ねる

Python のパッケージを作る __init__.py の役割と、絶対インポート / 相対インポートの使い分けを基礎から学びます。

アプリケーションが大きくなると、関連するモジュールを 1 つのフォルダにまとめて パッケージ として扱いたくなります。本記事では、パッケージの作り方と __init__.py の役割、from .module import ... のような 相対インポート を整理します。

パッケージとは __init__.py 入りのフォルダ

パッケージ とは、__init__.py という特別なファイルを含んだ フォルダ のことです。Python はこのファイルを見つけると、そのフォルダ全体を 1 つのパッケージとして扱い、外部から import フォルダ名 で読み込めるようにします。__init__.pyパッケージが import されたときに最初に実行される 場所で、ここで公開する関数やクラスを定義することが多いです。

パッケージの基本構造
my_package/ (パッケージ)
  • __init__.py — パッケージが import されたときに最初に実行されるファイル
  • calculation.py — モジュール(add / multiply)
  • string_utils.py — モジュール(format_name など)
my_package/ フォルダに __init__.py が入っているのでパッケージとして認識される。中の calculation.py などのモジュールは __init__.py が橋渡しして外に公開する。

__init__.py空ファイルでも構いません。空でも、フォルダにそのファイルがあるだけで Python はパッケージとして認識します。

__init__.py を介さず直接 import する

__init__.py空ファイル でも、パッケージ内のモジュールは 直接 import すれば呼び出せます。from パッケージ名.モジュール名 import 関数名 のように、ファイル位置をドットでつなぐ書き方です。

# my_package/__init__.py  ← 中身は空でも OK

# my_package/calculation.py
def add(a, b):
    return a + b


# main.py から呼ぶ
from my_package.calculation import add   # ← ファイル名 calculation まで明示する
print(add(1, 2))   # 3

このパターンでは、利用者が どのファイルに何があるか を知っている必要があります。後でファイル分割を変えると(例: calculation.py を 2 つに分けるなど)、利用側のコードも書き直さないといけません。次のセクションで紹介する __init__.py での再エクスポートは、これを 「パッケージ名直下から短い名前で呼べる」 形に整える仕組みです。

__init__.py で公開する関数を集める

__init__.py の中で from .モジュール名 import 関数名 と書いておくと、外部からは パッケージ名直下 にその関数があるかのように見えるようになります。たとえば __init__.pyfrom .calculation import add, multiply と書けば、外側のファイルからは from my_package import add, multiply と短く書けます。

__init__.py で再エクスポートして import を短くする
my_package/main.py__init__.pyfrom .calculationimport add, multiplycalculation.pydef add()def multiply()from my_packageimport addadd(1, 2)が呼べる経由引き上げ
calculation.py の add を __init__.py で引き上げて公開すると、main.py からはファイル名 calculation を意識せずに from my_package import add と短く書ける。

左に my_package/ フォルダが添付されています(📂 ファイルから calculation.py と __init__.py の中身を確認できます)。

① from my_package import add, multiply で 2 つの関数を読み込んでください。

② add(10, 20) と multiply(3, 4) の結果を print() で表示してください。

Python エディタ

コードを実行してください

公開 API を __init__.py に集める意義

利用者が触るのは __init__.py が公開した関数・クラスだけ、と決めておくと、内部のファイル分割を後から自由に変えても 利用側のコードを書き換えずに済みます。これは外側に対して カプセル化 を効かせる、パッケージ設計の基本パターンです。

from と import — 2 つの書き方

import 文には 2 つの書き方 があります — from パッケージ import 名前import パッケージ です。どちらも対象を読み込む点は同じですが、呼び出すときの書き方 が変わります。

from と import — スコープに入る名前が変わる
from my_pkg.calcimport addスコープに入る:add呼び方:add(1, 2)importmy_pkg.calcスコープに入る:my_pkg呼び方:my_pkg.calc.add(1, 2)
from パッケージ import 名前名前そのもの をスコープに取り込むのでそのまま呼べる。import パッケージパッケージ名のみ が入り、関数呼び出しは完全パスで書く必要がある。
# パターン 1: from ... import ...
from my_package.calculation import add
print(add(1, 2))   # add がそのまま使える


# パターン 2: import ...
import my_package.calculation
print(my_package.calculation.add(1, 2))   # 完全パスで呼ぶ必要がある


# パターン 2 + as エイリアス(長い名前を短くしたい)
import my_package.calculation as calc
print(calc.add(1, 2))
書き方スコープに入る名前呼び出し方
from my_package.calculation import addaddadd(1, 2)
import my_package.calculationmy_packagemy_package.calculation.add(1, 2)
import my_package.calculation as calccalccalc.add(1, 2)

よく使うのは from パッケージ import 名前 の形で、関数名を短く呼べるため main 側のコードが読みやすくなります。ただし、異なるパッケージが同じ名前の関数を持っている ときは import パッケージ の形でモジュール名を残しておくと、どちらの関数を呼んでいるかが一目で分かります。

from と import — main 側のスコープに何が入るか
from my_pkg.calc import add
  • add — 名前そのものが main 側に入る
  • 呼び方: add(1, 2) でそのまま使える
  • 短く書ける反面、add がどのパッケージ由来か一目で分からない
import my_pkg.calc
  • my_pkg — パッケージ名だけが main 側に入る
  • 呼び方: my_pkg.calc.add(1, 2) と完全パスで書く
  • 長くなる代わりに、my_pkg.calc.add で由来が明示される
from パッケージ import 名前名前そのもの を main 側のスコープに入れる (= 短く呼べる)。import パッケージパッケージ名のみ が入り、関数を呼ぶときは完全パスでドットをつなぐ (= どこから来たか追いやすい)。

添付の mathlib/ パッケージで 2 通りの書き方を試します。calculator.py には triple(n) が定義されています(📂 で確認)。

from ... import ... のパターン で triple を取り込み、triple(7) の結果を print() してください。

② 続いて、import ... as ... のパターン で mathlib.calculator を calc という別名でも取り込み、calc.triple(7) も print() してください。

Python エディタ

コードを実行してください

絶対インポートと相対インポート

パッケージ内のモジュール同士でお互いを参照したい、というケースを考えます。たとえば utility/validator.py から utility/helper.py を読み込みたいときの書き方は 2 通り あります — 絶対インポート相対インポート です。違いを理解するには、まず プロジェクトのルート が何を指すかを押さえる必要があります。

プロジェクトのルートとは
project/ ← ここがルート (main.py が置いてあるフォルダ)
  • main.py ← 最初に実行されるファイル
  • config.py ← アプリ全体の設定値
my_app/
  • __init__.pyimport my_app で最初に実行されるファイル
utility/
  • __init__.py
  • validator.py
  • helper.py
プロジェクトのルート = 最初に実行する main.py が置いてあるフォルダ。絶対インポート from my_app.utility import validatormy_app は、このルート直下 にある同名フォルダを指す。

プロジェクトのルート とは、python main.py のように 最初に実行する main.py が置いてあるフォルダ のことです。絶対インポート from my_app.utility import validator を書くと、Python は このルート直下 から my_app フォルダを探し、その中の utility/validator.py をたどります。フォルダ構成をドットでつないだもの が、絶対インポートのパスになります。

種類書き方意味
絶対インポートfrom my_app.utility import helperプロジェクトのルートからの完全パスで指定
相対インポートfrom . import helper今いるファイルからの相対位置で指定
相対インポート(親)from .. import config1 階層上のフォルダにあるファイルを指定
validator.py から helper.py を読む書き方
絶対インポートfrom my_app.utilityimport helperルートからの完全パス相対インポートfrom . importhelper今のフォルダを基準
同じパッケージ内の隣のモジュールを読むときは、絶対パスでも相対パスでも書ける。from . import. は「自分と同じフォルダ」を表す。

実行ファイル(main.py)から外部のパッケージを読み込むとき は絶対インポートを使い、パッケージ内部のモジュール同士の参照 には相対インポートを使う、という棲み分けが一般的です。相対インポートだと、後でパッケージ名(フォルダ名)を変えたときにも内部のコードを書き換えずに済みます。

# my_app/utility/validator.py
# 同じパッケージ内の helper.py を相対インポート
from .helper import log_message


def validate_user(user):
    if user.name and user.email:
        log_message("検証 OK")
        return True
    log_message("問題が発生しました")
    return False


# my_app/utility/helper.py
def log_message(message):
    print("[LOG]", message)


# 別パッケージにある config.py を読みたいときは、
# 1 つ上に上がる .. を使う:
# from ..config import get_config
上のコードのフォルダ構成
my_app/
  • config.pyfrom ..config import ... の対象
utility/
  • validator.pyfrom .helper import log_message を書く側
  • helper.pylog_message(...) を提供する側
validator.py と helper.py は 同じ utility/ フォルダの中 に並んでいる。だから validator.py の from .helper import log_message. は「このフォルダ (= utility/)」を指す。config.py1 階層上の my_app/ にあるので、validator から見ると ..config (.. = 1 階層上) で参照できる。

実行ファイルから相対インポートはできない

python main.py のように 直接実行 されるファイルからは相対インポートを書けません(ImportError になります)。相対インポートは「自分が どこかのパッケージの一員 として読み込まれている」前提で動く仕組みのためです。実行ファイル側からは、必ず絶対インポート(from my_app.utility import validate_user)で書きましょう。

添付の shop/ パッケージで絶対インポートと相対インポートの組み合わせを試します。📂 を開くと shop/__init__.py は空 で、Cartto_yen もパッケージ直下から見えていません。

① まず main.py をそのまま実行してください — ImportError になります(Cartto_yen がどこにも公開されていないため)。

② 次に 📂 から shop/__init__.py を開いて、from .cart import Cartfrom .formatter import to_yen相対インポート (. は今のパッケージ = shop) で書いて保存してください。

③ main.py に Cart の利用コード — Cart() を作って apple 100円・orange 200円 を追加 → 合計を to_yen() で整形して print() — を書いて再実行してください。main 側は 絶対インポート、shop 内部は 相対インポート という棲み分けです。

Python エディタ

コードを実行してください

実プロジェクト風の構成

ここまでのルールで、実際のアプリでよく見るフォルダ構成が組み立てられます。たとえば、設定・データベース・ユーティリティの 3 つのパッケージに分けた構成は次のようになります。

実プロジェクトに近いフォルダ構成
project/ (プロジェクトルート)
  • main.py — 実行ファイル(直接 python で起動する側)
  • config.py — アプリ全体の設定値
my_app/
  • __init__.py — my_app パッケージの公開 API
database/
  • __init__.py
  • connection.py / models.py
utility/
  • __init__.py
  • validator.py / helper.py
実行ファイル main.py から my_app/ パッケージ全体を読み込み、内部のモジュール同士は相対インポートで結ぶ。各サブフォルダにも __init__.py を置いて、それぞれの公開 API をまとめる。

main.py からは from my_app.utility import validate_user のように 絶対インポート で公開関数を呼び、utility/ の内側にある validator.py から helper.py を呼ぶときは from .helper import log_message相対インポート で書く、という役割分担になります。

絶対と相対の境界
my_app/utility/main.pyvalidator.pyhelper.py絶対相対
main.py から utility パッケージへは 絶対(ルートからのパス)、utility 内部の validator → helper は 相対(自分基準のパス)で結ぶ。境界を意識すると後でフォルダ名を変えても影響範囲が狭い。

my_app/utility/ パッケージの validator.py を 自分で実装 して、main.py から呼び出します(📂 ファイルから validator.py を開いて編集 → Cmd+S または保存)。helper.py は完成済みです。

① validator.py の validate_user(email) を実装してください:

- __init__.pyで from .helper import log_message相対インポート で同じフォルダの helper.py を読み込む

- email に @. が両方含まれていれば log_message("検証 OK: " + email) を呼び True を返す

- そうでなければ log_message("問題が発生しました: " + email) を呼び False を返す

② main.py で from my_app.utility import validate_user絶対インポート で読み込み、validate_user("taro@example.com") の結果を print() してください。

Python エディタ

コードを実行してください

ここからは応用 — つまずいたら戻ってきて OK

次の演習は 2 つのパッケージを並行で組み立てる集大成課題 です。__init__.py の再エクスポートが手に馴染んでいて、相対インポート / 絶対インポートの違いがあやしくない 状態で進むのが理想です。詰まったら直前の validator.py 演習や、上の 「実プロジェクト風の構成」 の図に戻って整理してから挑戦してください。

複数フォルダ構成にチャレンジ

ここまでのルールを使って、2 つのパッケージを並行で組み立てる 演習に挑戦してみましょう。商品カタログを扱う catalog/ パッケージと、請求書を整形する billing/ パッケージを別々のフォルダで管理し、main.py から両方を呼び出して 1 つの注文処理を完成させます。役割をフォルダごとに分けると、後で「商品データだけ差し替えたい」「請求書の書式だけ変えたい」となっても影響範囲を そのフォルダ内に閉じ込められる のが利点です。

プロジェクトのフォルダ構成 (catalog と billing の 2 パッケージ)
project/ ← プロジェクトのルート
  • main.py — 実行ファイル (両パッケージを使ってオーダー処理)
catalog/
  • __init__.pyfrom .products import get_price で再エクスポート
  • products.pyget_price(name) を実装する
billing/
  • __init__.pyfrom .invoice import format_invoice で再エクスポート
  • invoice.pyformat_invoice(name, qty, unit_price) を実装する
catalog/ には商品データ (products.py)、billing/ には請求書整形 (invoice.py) を置く。各 __init__.py が公開 API を再エクスポートし、main.py からは from catalog import get_pricefrom billing import format_invoice の 2 つの絶対インポートで両方を呼び出せる。
main.py が 2 つのパッケージを束ねる流れ
catalogget_price()main.py両方を組み合わせるbillingformat_invoice()from catalog import get_pricefrom billing import ...
main.py から catalog を 絶対インポート で読み込んで単価を引き、billing を 絶対インポート で読み込んで請求書を整形。各パッケージ内部では __init__.py.products / .invoice相対インポート で再エクスポート。

添付の catalog/billing/ の 2 つのパッケージを __init__.py も含めて自分で完成させ、main.py から両方を絶対インポートして注文処理を組み立てます (📂 から各ファイルを開いて編集 → Cmd+S または保存)。

① catalog/products.py に get_price(name) を実装 — "apple" → 100、"orange" → 150、それ以外 → 0 を返す (dict + dict.get(name, 0) が便利)。

② catalog/__init__.py に from .products import get_price を書いて、外側から from catalog import get_price で呼べるようにする (相対インポート)。

③ billing/invoice.py に format_invoice(name, qty, unit_price) を実装 — qty * unit_price で合計を計算し、"apple x 3 = ¥300" のような文字列を返す。

④ billing/__init__.py に from .invoice import format_invoice を書く。

⑤ main.py で from catalog import get_pricefrom billing import format_invoice を絶対インポートし、商品 "apple" を 3 個注文するとして catalog から単価を引いて → billing で整形 → print() してください。

Python エディタ

コードを実行してください

ここから先は補足 — 実務では稀

__all__ を扱う以下のセクションは情報目的の補足です。from package import * を実際に使う機会は実務でほとんどなく、本筋の理解には影響しません。「明示的に名前を書く」 import の使い方さえ押さえていれば、ここはサッと読んで進めても OK です。

__all__ で from パッケージ import * を制御する

from my_package import * のように アスタリスクで全部読み込む 書き方をされたとき、何を公開するかは __init__.py 内の __all__ で制御できます。__all__ = ["add"] と書いておくと、* インポートでは add だけが取り込まれ、他の関数は取り込まれません。

__all__ で公開する名前を絞る
__init__.pyfrom .calc importadd, multiply__all__ = ["add"]from pkgimport *add→ 取り込まれるmultiply→ 取り込まれない(NameError)
__all__ = ["add"] を __init__.py に書くと、from パッケージ import * で取り込まれるのは add のみ。multiply は除外される(明示的に名前を指定すれば取り込める)。
# my_package/__init__.py
from .calculation import add, multiply

__all__ = ["add"]   # * では add しか公開しない

# 利用側
# from my_package import *
# add(1, 2)        # OK
# multiply(1, 2)   # NameError(* では取り込まれていない)

実務では * インポートは避ける

from my_package import *何が読み込まれたか一目で分からない ため、実務ではほとんど使いません。from my_package import add, multiply のように 明示的に名前を書く のが基本です。__all__ は「誰かが * を使った場合の保険」と捉えておけば十分です。

添付の bundle/ パッケージで __all__ の挙動を確認します。📂 から bundle/__init__.py を見ると、add / multiply の両方を取り込みつつ __all__ = ["add"] で公開を絞っています。

① main.py で from bundle import * を実行し、add(2, 3) を print() してください。

② 続けて multiply(2, 3) を呼び出すコードを try/except で囲み、NameError になることを確認してください (この演習は CPython 互換の Pyodide ランタイムを使用します — 初回のみロードに 5〜15 秒かかります)。

Python エディタ

コードを実行してください

この記事では、__init__.py で複数モジュールを 1 つの パッケージ として束ねる書き方、from パッケージ import 名前import パッケージ の 2 通りの書き方の違い、絶対インポートと相対インポート の使い分け、そして実プロジェクトに近いフォルダ構成を確認しました。

QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1パッケージ として認識されるために、フォルダの中に必ず置くべきファイルはどれですか?

Q2my_app/utility/validator.py から、同じ utility フォルダ内の helper.py を読み込みたいとき、相対インポートとして正しい書き方はどれですか?

Q3実行ファイルpython main.py で直接起動するファイル)の中で相対インポート(from . import xxx)を書くと、何が起きますか?