web-dev-qa-db-ja.com

すべてのレベルで__init__.pyが必要なのはなぜですか?

.が現在の作業ディレクトリである次のディレクトリ構造があるとします

.
\---foo
    \---bar
        \---__init__.py
        \---baz.py

python -c "import foo.bar.baz"を実行すると、

Traceback (most recent call last):
  File "<string>", line 1
ImportError: No module named foo.bar.baz

私がecho "" > foo/__init__.pyの場合、上記のコマンドは機能します。

私は何か間違ったことをしていますか、それとも__init__.pyのポイントを誤解していますか?私はそれがすべきでない場所に存在するモジュールを停止することだと思いました、例えばstringという名前のディレクトリですが、私の例でfoostringに置き換えると、使用してはならないモジュールを作成せざるを得ないようです。階層のより深いファイルを参照します。

更新

私は__init__.pyを生成し、ディレクトリ構造を適用するビルドシステムを使用しています。階層を変更することはできますが、__init__.pyを自分で追加することをお勧めします。質問を少し変更するために、なぜpythonパッケージを最上位ではなくすべてのレベルで必要とするのですか?pythonパスまたはpythonパス?

13
quittle

はい、ディレクトリをモジュールとして扱う場合は、このファイルが必要です。

__init__.pyファイルは、Pythonディレクトリをパッケージを含むものとして扱うために必要です。これは、文字列などの一般的な名前のディレクトリが、発生する有効なモジュールを誤って非表示にしないようにするために行われます最も単純な場合、__init__.pyは空のファイルにすることができますが、パッケージの初期化コードを実行したり、後で説明する__all__変数を設定したりすることもできます。

https://docs.python.org/3/tutorial/modules.html#packages

空でない__init__.pyを作成しようとしています。モジュールを文書化し、最初のレベルで最も有用なオブジェクト(クラス/関数)を提供することにより、ユーザー/開発者のネストされたインポートを取り除く可能性が高い... ...実際には可能な限りシンプルに使用する対照的に-としましょう-Java imports

質問の更新後に編集

デフォルトのインポーター/ファインダー(sys.meta_pathを確認)は次のとおりです。

  1. BuiltinImporter -組み込みモジュールを検索/ロードします
  2. FrozenImporter -凍結されたモジュールを検索/ロードします(例:* .pyc)
  3. PathFinder -興味のあるもの。ファイルシステムに基づいてモジュールを検索/ロードできます。

3番目は__init__.pyです(実際にはFrozenImporterも)。

PathFinderは、sys.pathからのパス(およびパッケージで定義されている__path__)でモジュールを検索します。モジュールは、スタンドアロンpythonファイル(検索されたパスのルートにある場合)または__init__.pyのディレクトリのいずれかです。

あなたの例を参照してください:

foo/
  bar/
    __init__.py
    baz.py
  • _init__.pyfoo/で作成すると、foo.bar.bazが使用可能になります(お伝えしたとおり)。

  • foo/sys.pathを追加するか、PYTHONPATH=foo/を介して渡すと、bar.bazが使用可能になります(親モジュールfooがないことに注意してください)。

  • 独自の Finder (およびローダー)を作成すると、たとえば、どこにいても必要なファイルをロードできます。それはあなたに大きな力を与えます。たとえば、 stack-overflow-import を見て、SOの検索結果に基づいてコードを公開します。

8
kwarunek