1
0

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は省略せずに作成しよう

Posted at

init.pyとは?

まず__init__.pyとは、Pythonのディレクトリをパッケージとして認識させるためのファイルです。これにより、ディレクトリ内のモジュールをパッケージの一部として管理できるようになります。

1. パッケージの認識

  • __init__.pyは、ディレクトリをPythonのパッケージとして認識させるためのファイルです。
  • パッケージとは、モジュールをまとめて整理するためのディレクトリのことです。
  • Python 3.3以降では、__init__.pyがなくてもディレクトリはパッケージとして認識されますが、特別な初期化処理を行いたい場合や、古いバージョンとの互換性を確保したい場合には依然として使用されます。

2. 初期化処理

  • パッケージがインポートされる際に実行される初期化コードを記述できます。
  • 例えば、必要なモジュールやクラスのインポート、設定の初期化、ログの設定などを行うことができます。
print("mypackage is imported")

from .module1 import func1
from .module2 import Class2

上記の例では、mypackageをインポートするとmodule1func1module2Class2を直接使えるようになります。

3. 名前空間の整理

  • パッケージの公開インターフェースを整理する役割もあります。
  • 不要な内部モジュールを隠したり、パッケージのユーザーにとって重要な機能だけをエクスポートすることができます。
__all__ = ["func1", "Class2"]

__all__を指定すると、from mypackage import *のような形でインポートする際に指定された名前だけがインポートされます。

4. パッケージの階層化

  • サブパッケージを持つパッケージでは、親と子のパッケージ間でインポートを整理する役割も果たします。
  • 親パッケージがサブパッケージを動的に読み込む際にも活用できます。

5. 空の__init__.py

  • __init__.pyが空の場合もあります。この場合、そのディレクトリが単なるパッケージであることを示し、特別な初期化処理を行わないという意味になります。

__init__.pyって必要? - 省略して困った話

以前、「書かなくても動いてしまうから省略してもいいのかな?」と思った事がありました。しかし、実際に省略したことで以下の問題に直面しました。

  1. unittest がテストモジュールを認識しない

    • unittest discover を使ってテストを実行しようとしたところ、一部のテストが実行されませんでした。
    • __init__.py を追加したら正常に動作しました。
  2. Lint ツールがモジュールを正しく検出しない

    • flake8mypy を実行すると、一部のモジュールが ModuleNotFoundError になった。
    • __init__.py を追加したらエラーが解消。
  3. 複数のモジュールが存在するプロジェクトで import エラーが発生

    • from mypackage import module1 のような import が動作しないことがあった。
    • __init__.py を入れたら問題なく動作した。

この経験から、「__init__.py を省略すると、意図せず Namespace Package の機能を使ってしまうことになる」と実感しました。以降、面倒くさがらずに __init__.py を作成するようにしています。


Python 3.3以降では省略しても問題ない?

Python 3.3 では、PEP 420 によって「Implicit Namespace Package」が導入されました。これにより、__init__.py がなくても Python のパッケージとして認識されるようになりました。

ただ、実際には省略せずに__init__.pyを作成するが正しいです。

PEP 420 (Implicit Namespace Package) の内容を詳しく見てみると、__init__.py を省略してもパッケージとして認識される」 という点が強調されているため、これが「__init__.py は不要になった」と誤解される原因になったと考えられます。

PEP 420 の主なポイント

PEP 420 の公式ドキュメントでは、以下のような内容が紹介されています。

1. __init__.py を省略してもパッケージとして認識される

PEP 420 では、以下のように明記されています。

"A package is now simply a directory that is a container for modules or subpackages."
(パッケージは単に、モジュールやサブパッケージを含むディレクトリになった)

以前は __init__.py が必須だったのに対し、「ディレクトリであればパッケージとして扱われる」 という説明がされているため、これを見た開発者は 「もう __init__.py を作らなくてもよい」 と思ってしまう可能性があります。


2. sys.path にある複数のディレクトリを統合できる

PEP 420 の主な目的は、Namespace Package のサポートです。例えば、以下のようなディレクトリ構造があったとします。

/usr/lib/python3.3/site-packages/mypackage/
    module1.py

/home/user/project/mypackage/
    module2.py

この場合、Python 3.3 以前は __init__.py がないと mypackage はパッケージとして認識されませんでした。しかし、PEP 420 では __init__.py がなくても mypackage というパッケージが統合され、以下のように import できるようになります。

import mypackage.module1
import mypackage.module2

これが「__init__.py は不要」と誤解される理由の一つです。


3. __init__.py を使うべき場面の説明が不十分

PEP 420 では、Namespace Package は通常のパッケージとは異なるもの であることが説明されていますが、「従来のパッケージでは __init__.py を作成するのが推奨される」 という点が強調されていません。

そのため、以下のような誤解が生じます。

誤解:「Python 3.3 以降は __init__.py を作らなくてもいい」
本来の意図:「Namespace Package では __init__.py を省略できるが、通常のパッケージでは __init__.py を作るべき」


__init__.pyを省略することによる弊害

  1. importが遅くなる可能性

    • Namespace Packageは通常のパッケージと異なる仕組みでモジュールを探索するため、処理が遅くなる場合がある。
    • 探索順序の違いから問題が発生するリスクもある。
  2. ツールの非対応

    • unittestなどの標準ツールは、__init__.pyのないディレクトリをモジュールとして認識しない。
    • 自動でモジュールを探すツール(例: Linter)もNamespace Packageに対応していない場合が多い。
  3. 効率低下のリスク

    • Namespace Package対応のために、すべてのディレクトリを再帰的に探索すると、処理速度が低下する。
    • 特に大量のファイルが含まれるディレクトリ(例: node_modules)やネットワーク上のディレクトリでは、探索が極めて遅くなる。

結論

  • __init__.pyを明示的に記述することが推奨される。
  • Namespace Packageは特殊なケース向けで、一般的なパッケージ開発では使うべきではない。
1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?