web-dev-qa-db-ja.com

ModuleNotFoundError: '__main __。xxxx'という名前のモジュールはありません。 「__main__」はパッケージではありません

現在、Python3で動作し、絶対インポートを使用して1つのモジュールを別のモジュールにインポートしようとしていますが、エラーModuleNotFoundError: No module named '__main__.moduleB'; '__main__' is not a packageが表示されます。このプロジェクト構造を考えてみましょう

proj
    __init__.py3 (empty)
    moduleA.py3
    moduleB.py3

moduleA.py3

from .moduleB import ModuleB
ModuleB.hello()

moduleB.py3

class ModuleB:
    def hello():
        print("hello world")

その後、python3 moduleA.py3を実行するとエラーが発生します。ここで何を変更する必要がありますか?

42
mpseligson

.moduleBは相対的なインポートです。相対は、親モジュールが最初にインポートまたはロードされたときにのみ機能します。つまり、現在のランタイム環境のどこかにprojをインポートする必要があります。コマンドpython3 moduleA.py3を使用している場合、親モジュールをインポートする機会はありません。あなたはできる:

  • from proj.moduleB import moduleBまたは
  • run.pyを呼び出す別のスクリプト、たとえばfrom proj import moduleAを作成できます

Pythonの素晴らしい土地への旅に幸運を。

36

Md-sabuj-sarkerの答えに加えて、 Pythonモジュールのドキュメント には本当に良い例があります。

これは、ドキュメントが intra-package-references について述べていることです:

相対的なインポートは、現在のモジュールの名前に基づいていることに注意してください。メインモジュールの名前は常に"__main__"であるため、Pythonアプリケーションのメインモジュールとして使用するモジュールは常に絶対インポートを使用する必要があります。

python3 moduleA.py3を実行する場合、moduleAがメインモジュールとして使用されるため、絶対インポートの使用は正しいことのように見えます。

ただし、何らかの理由でパッケージにパッケージと同じ名前のモジュールファイルが含まれている場合(少なくとも、Python 3.7では)、この絶対インポート(from package.module import something)が失敗することに注意してください。したがって、たとえば、次のような場合は失敗します(OPの例を使用):

proj/
    __init__.py (empty)
    proj.py (same name as package)
    moduleA.py
    moduleB.py

その場合、次のようになります。

ModuleNotFoundError: No module named 'proj.moduleB'; 'proj' is not a package

または、提案されているように、.from .moduleB importを削除することができます here および here 、これは私のPyCharm(2018.2.4 )これを「未解決の参照」としてマークし、オートコンプリートに失敗します。

17
djvg

序文

私は、実際にpipでインストールできるPythonパッケージであるプロジェクトを開発していますが、コマンドも公開していますラインインターフェイス。 pip install .を使用してプロジェクトをインストールした後、プロジェクトの実行に問題はありませんが、プロジェクトファイルのいずれかを変更した後に毎回これを行うのは誰ですか?単純なpython mypackage/main.pyで全体を実行する必要がありました。

/my-project
    - README.md
    - setup.py
    /mypackage
      - __init__.py
      - main.py
      - common.py

同じ問題のさまざまな顔

main.pyモジュールからcommon.pyのいくつかの関数をインポートしようとしました。さまざまなエラーが発生するさまざまな構成を試しましたが、観察結果を共有し、今後のメモも残しておきたいと思います。

相対的なインポート

私が最初に試したのは相対的なインポートでした:

from .common import my_func

python mypackage/main.pyという単純なアプリケーションを実行しました。残念ながら、これにより次のエラーが発生しました。

ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package

この問題の原因は、main.pypythonコマンドによって直接実行されたため、__main__という名前のメインモジュールになったことです。この情報を、使用した相対インポートに関連付けた場合、エラーメッセージ__main__.commonにある内容を取得します。これは Pythonドキュメント で説明されています:

相対的なインポートは、現在のモジュールの名前に基づいていることに注意してください。メインモジュールの名前は常に__main__であるため、Pythonアプリケーションのメインモジュールとして使用するモジュールは常に絶対インポートを使用する必要があります。

pip install .を使用してパッケージをインストールして実行すると、完全に正常に機能しました。 Pythonコンソールにmypackage.mainモジュールをインポートすることもできました。そのため、直接実行するだけでは問題があるようです。

絶対インポート

ドキュメントのアドバイスに従って、インポートステートメントを別のものに変更しましょう。

from common import my_func

これを以前のように実行しようとすると:python mypackage/main.py、それは期待通りに動作します!ただし、私のように、pipを使用してインストールした後、スタンドアロンのコマンドラインツールとして動作する必要があるものを開発する場合は注意が必要です。 pip install .でパッケージをインストールし、実行しようとしました...

ModuleNotFoundError: No module named 'common'

さらに悪いことに、Pythonコンソールを開いてmainモジュールを手動でインポートしようとすると(import mypackage.main)、上記と同じエラーが発生しました。その理由は簡単です:commonはもはや相対的なインポートではないので、Pythonはインストールされたパッケージでそれを見つけようとします。そのようなパッケージはありません。それが失敗する理由です。

絶対インポートを使用したソリューションは、pythonコマンドで実行される典型的なPythonアプリを作成する場合にのみうまく機能します。

パッケージ名でインポートする

commonモジュールをインポートする3番目の可能性もあります。

from mypackage.common import my_func

これは、mypackageのコンテキストから行う限り、relative importアプローチとあまり変わりません。繰り返しますが、python mypackage/main.pyでこれを実行しようとすると、同様の結果になります。

ModuleNotFoundError: No module named 'mypackage'

どんなにいらいらするかもしれません、通訳は正しいです、あなたはそのようなパッケージをインストールしていません。

ソリューション

シンプルなPythonアプリの場合

絶対インポート(ドットなし)を使用するだけで、すべて問題ありません。

開発中のインストール可能なPythonアプリの場合

アプリのインストール時にこのように必要になるため、相対インポート、または先頭にパッケージ名を使用したインポートを使用します。開発でそのようなモジュールを実行する場合、Pythonは-mオプションで実行できます:

-m mod : run library module as a script (terminates option list)

python mypackage/main.pyの代わりに、python -m mypackage.mainのようにします。

1
itachi

モジュールをインポートする前にこれを行うことができます:

moduleA.py3

import os
import re
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from moduleB import ModuleB
ModuleB.hello()

現在のディレクトリを環境ディレクトリに追加します

0
Toby