スクリプトとモジュール
ここに説明があります。簡単に言うと、Python ファイルを直接実行することと、そのファイルを別の場所からインポートすることには大きな違いがあります。 ファイルがどのディレクトリにあるかを知っているだけでは、Python がどのパッケージにあると考えるかはわかりません。 さらに、ファイルを Python にロードする方法 (実行またはインポート) にも依存します。
Python ファイルをロードするには、トップレベル スクリプトとして、またはモジュールとして 2 つの方法があります。python myfile.py
コマンド ラインに入力するなどしてファイルを直接実行すると、ファイルは最上位のスクリプトとして読み込まれます。import
ステートメントが他のファイル内で検出されると、モジュールとしてロードされます。一度に作成できる最上位スクリプトは 1 つだけです。最上位のスクリプトは、作業を開始するために実行した Python ファイルです。
ネーミング
ファイルがロードされると、名前が付けられます (__name__
属性に保存されます)。最上位スクリプトとしてロードされた場合、その名前は__main__
. モジュールとしてロードされた場合、その名前はファイル名の前に、その一部であるパッケージ/サブパッケージの名前がドットで区切られて続きます。
たとえば、あなたの例では:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
インポートした場合moduleX
(注:直接実行ではなく、インポート済み)、その名前は になりますpackage.subpackage1.moduleX
。をインポートした場合moduleA
、その名前は になりますpackage.moduleA
。ただし、コマンド ラインから直接実行する moduleX
と、その名前は代わりに になり、コマンド ラインから__main__
直接実行するとmoduleA
、その名前は になります__main__
。モジュールが最上位スクリプトとして実行されると、通常の名前が失われ、代わりに__main__
.
含まれているパッケージを介さずにモジュールにアクセスする
追加のしわがあります: モジュールの名前は、それが含まれているディレクトリから「直接」インポートされたか、パッケージを介してインポートされたかによって異なります。これは、ディレクトリで Python を実行し、同じディレクトリ (またはそのサブディレクトリ) にファイルをインポートしようとした場合にのみ違いが生じます。たとえば、ディレクトリで Python インタープリターを起動してpackage/subpackage1
を実行するimport moduleX
と、 の名前はではなく にmoduleX
なります。これは、インタプリタが対話的に入力されると、Python が現在のディレクトリを検索パスに追加するためです。インポートするモジュールが現在のディレクトリで見つかった場合、そのディレクトリがパッケージの一部であることは認識されず、パッケージ情報はモジュール名の一部になりません。moduleX
package.subpackage1.moduleX
特殊なケースとして、インタプリタを対話的に実行する場合があります (たとえば、python
その場で Python コードを入力して入力を開始するなど)。この場合、そのインタラクティブ セッションの名前は です__main__
。
エラー メッセージの重要な点は次のとおりです。モジュールの名前にドットがない場合、それはパッケージの一部とは見なされません。ファイルが実際にディスク上のどこにあるかは問題ではありません。重要なのはその名前が何であるかであり、その名前はロード方法によって異なります。
次に、質問に含めた引用を見てください。
相対インポートでは、モジュールの name 属性を使用して、パッケージ階層内でのそのモジュールの位置を決定します。モジュールの名前にパッケージ情報が含まれていない場合 (たとえば、「main」に設定されている場合)、モジュールが実際にファイル システム上のどこにあるかに関係なく、モジュールが最上位モジュールであるかのように相対インポートが解決されます。
相対インポート...
相対インポートでは、モジュールの名前を使用して、パッケージ内の場所を決定します。のような相対インポートを使用する場合from .. import foo
、ドットはパッケージ階層のいくつかのレベルを上げることを示します。たとえば、現在のモジュールの名前がpackage.subpackage1.moduleX
である場合、..moduleA
を意味しpackage.moduleA
ます。afrom .. import
が機能するには、モジュールの名前に少なくともimport
ステートメント内にある数と同じ数のドットが含まれている必要があります。
...パッケージ内でのみ相対的です
ただし、モジュールの名前が の場合__main__
、パッケージに含まれているとは見なされません。from .. import
その名前にはドットがないため、その中にステートメントを使用することはできません。そうしようとすると、「非パッケージでの相対インポート」エラーが発生します。
スクリプトは相対をインポートできません
あなたがおそらくしたことはmoduleX
、コマンドラインから実行などを試みたことです。これを行ったとき、その名前は に設定されました__main__
。これは、その名前がパッケージ内にあることを明らかにしないため、その中の相対インポートが失敗することを意味します。これは、モジュールがあるディレクトリから Python を実行し、そのモジュールをインポートしようとした場合にも発生することに注意してください。パッケージの一部。
また、対話型インタープリターを実行すると、その対話型セッションの「名前」は常に__main__
. したがって、対話セッションから直接相対インポートを行うことはできません。相対インポートは、モジュール ファイル内でのみ使用できます。
2 つのソリューション:
本当に直接実行したいmoduleX
が、それでもパッケージの一部と見なしたい場合は、python -m package.subpackage1.moduleX
. は-m
、最上位のスクリプトとしてではなく、モジュールとしてロードするように Python に指示します。
または、実際には を実行したくなくて、たとえば内の関数を使用する他のスクリプトを実行したいだけかも しれません。その場合は、ディレクトリ内ではなく別の場所に置いて実行します。内部で次のようなことを行うと、正常に機能します。moduleX
myfile.py
moduleX
myfile.py
package
myfile.py
from package.moduleA import spam
ノート
これらのソリューションのいずれについても、パッケージ ディレクトリ (このpackage
例では) は Python モジュールの検索パス ( ) からアクセスできる必要がありますsys.path
。そうでない場合、パッケージ内の何も確実に使用することはできません。
Python 2.6 以降、パッケージ解決のためのモジュールの「名前」は、その__name__
属性だけでなく、属性によっても決定され__package__
ます。そのため、明示的なシンボル__name__
を使用してモジュールの「名前」を参照することは避けています。Python 2.6 以降、モジュールの「名前」は事実上__package__ + '.' + __name__
であるか、または単に で__name__
ある場合のみ__package__
ですNone
。)