コンテンツにスキップ

パッケージ

モジュールを使うことで関数やクラスをまとめることができますが、1 つのモジュール内にたくさんの定義を含めてしまうとコードが長くなってしまい分かりづらくなってしまいます。そういうときはファイルを分割して複数のモジュールを作成し、それを 1 つのディレクトリに集約することで綺麗に整理することができます。このように複数のモジュールを集約したディレクトリのことをパッケージといいます。

モジュールとパッケージの関係はファイルシステムでいうところのファイルとディレクトリの関係に一致します。

ファイルシステム Python
ファイル モジュール
ディレクトリ パッケージ

ファイル・ディレクトリのことを Python の世界ではモジュール・パッケージと呼んでいると理解して概ね問題ありません。

パッケージの作り方

パッケージはディレクトリのことだと説明しましたが、単に Python のソースコードをディレクトリに集約しただけではパッケージにはなりません。ディレクトリをパッケージとして扱うためには __init__.py というファイルをディレクトリ内に用意しておく必要があります。

example
├── __init__.py     # これがないとパッケージとは呼べない
├── a.py
└── b.py

__init__.py は空ファイルとして作成してもらって問題ありません。Python のソースコードをディレクトリに集約するときは必ず __init__.py を作るようにしましょう。

パッケージを使用する

パッケージもモジュールと同様、他のファイルに取り込まれることを想定した機能なので import 構文を使って取り込む ことができます。いま、パッケージの構成が次のようになっていたとしましょう。

example
├── __init__.py
├── a.py
│  └── def fib(n)
└── b.py

このとき、関数 fib(n) を呼び出したいときには次のようにします。

#!/usr/bin/env python


import example.a


def main():
    example.a.fib(10)


if __name__ == '__main__':
    main()

パッケージ名.モジュール名.関数名 のように . で区切って関数にアクセスすることができます。ちなみにパッケージ内にパッケージが含まれていても問題ありません。

モジュール・パッケージ名の命名規則

モジュール名・パッケージ名に - を使用するのは避けましょう。なぜなら xxx-yyy というモジュール・パッケージを作ったとき

import xxx-yyy

のように import することになりますが - が引き算だと解釈されてしまいます。一般的に命名規則は次のようなルールになっています。

  • 全て小文字
  • パッケージ名に区切り文字は禁止
  • モジュール名の区切り文字は _ を使用

モジュール名であっても区切り文字はできるだけ使用しない方が好まれます。パッケージ名は例え複数語であっても区切り文字は使用しません。

__init__.py

__init__.py というファイルがどのような働きをするのか見ていきたいと思います。上記のサンプルにある

import example.a

というインポートを下記のように変更すると example.a.fib() の参照が正しくできなくなります。

import example

両者の違いはインポートにモジュール名 example.a を指定しているか、パッケージ名 example を指定しているかにあります。インポートでパッケージ名を指定したときは example 配下にある __init__.py を探してインポートを実行するという振る舞いをします。

import example  # example/__init__.py を参照する

もし __init__.py 内に何も記述がなければ import example では何も取り込まれないことになります。そのため example.a.fib() の参照はエラーになってしまいます。たとえ example ディレクトリ配下に a.py があったとしても Python からは __init__.py の定義に従ってパッケージの階層を参照しているということです。

これに対して import example.a の場合だとうまくいくのは、モジュール example/a.py を直接インポートしており __init__.py の参照が起こらないからです。

import example として example.a.fib() を参照できるようにするためには __init__.py 内でモジュール a が参照できるようにしてあげる必要があります。これは下記のようにすることで実現できます。

example/__init__.py

from . import a

これは __init__.py と同一のディレクトリ階層から a をインポートするという構文で 相対インポート といいます。こうすることで __init__.py 内でモジュール a が参照できるようになるため import example としても example.a.fib() が参照できるようになります。

モジュール検索パス

__init__.py 内の記述を

import a

と書いてもうまくいきません。 import example としてもモジュール a が見つからないというエラーが起こってしまいます。これは Python がモジュールを探しに行くときに、決まったルールで検索をしているからです。Python はモジュールを探しに行くときに次の順序でモジュールを検索します。

  1. ビルトインモジュール(Python に最初から組み込まれたモジュール)
  2. python コマンドに渡したファイルのあるディレクトリ直下

例えばファイル構成が下記のようになっていた場合 python main.py と実行して Python がモジュールを探しに行くディレクトリは root 直下になります。

root    # ここ
├── example     # ここは探しに行かない
│  ├── __init__.py
│  └── a.py
└── main.py

ソースコードのどの場所で import a を書いても root 直下から a.py を探そうとします。相対インポートはこのルールに従わずにモジュールを検索してくれるため、うまくいくということです。