2

この例外がPython3インタープリターによって発生する正確なルールは何ですか?

それについてはたくさんのSOの質問があり、優れた答えがありますが、この例外が発生したときの状況を明確で、一般的で、論理的に正確に定義できるものは見つかりませんでした。

ドキュメントも明確ではないようです。それは言う:

例外ImportError

importステートメントがモジュール定義を見つけられなかった場合、またはfrom ... importインポートされる名前を見つけられなかった場合に発生します。

しかし、これは次の例と矛盾しているようです。

私は特定のケースではなく一般的な定義を求めるつもりでしたが、私の懸念を明確にするために、ここに例があります:

# code/t.py:
from code import d

# code/d.py
from code import t

t.pyコマンドラインからモジュールを実行すると、になりImportError: cannot import name dます。

一方、次のコードでは例外は発生しません。

# code/t.py:
import code.d

# code/d.py
import code.t

常に、__init__.pyは空です。

この例では、importステートメントで言及されているモジュールまたは名前はとのみでtありd、両方とも明確に検出されました。モジュール内の名前dが見つからないことがドキュメントに示されている場合、それは確かに明らかではありません。NameError: name ... is not definedそれに加えて、例外ではなく例外が発生することを期待していImportErrorます。

4

3 に答える 3

3

abcパッケージでxyzあり、がモジュールであり、がを含まないを定義している場合abc、は__init__.py実行できませんが、は実行できます。__all__xyzfrom abc import xyzimport abc.xyz

編集:簡単な答えは:あなたの問題はあなたの輸入が循環的であるということです。モジュールtとdは、相互にインポートしようとします。これは機能しません。しないでください。以下で全体を説明しますが、説明はかなり長いです。

ImportErrorが発生する理由を理解するには、コードの実行を追跡してみてください。最後の部分だけでなく、完全なトレースバックを見ると、それが何をしているのかがわかります。あなたのセットアップで私はこのようなトレースバックを取得します(私はパッケージを「コード」ではなく「テストパック」と呼びました):

Traceback (most recent call last):
  File "t.py", line 1, in <module>
    from testpack import d
  File "C:\Documents and Settings\BrenBarn\My Documents\Python\testpack\d.py", line 1, in <module>
    from testpack import t
  File "C:\Documents and Settings\BrenBarn\My Documents\Python\testpack\t.py", line 1, in <module>
    from testpack import d
ImportError: cannot import name d

ここでPythonが何をしているのかを見ることができます。

  1. ロードt.py時に、最初に表示されるのはですfrom testpack import d
  2. その時点で、Pythonはd.pyファイルを実行してそのモジュールをロードします。
  3. しかし、最初に見つかるのはですfrom testpack import t
  4. すでにt.py一度ロードされていますが、メインスクリプトとしてのtはモジュールとしてのtとは異なるため、t.py再度ロードを試みます。
  5. 最初に表示されるのは、です。これはfrom testpack import d、をロードしようとする必要があることを意味しますd.py。。。しかし、それはすでにステップ2でロードバックを試みていました。インポートしようとすると、再度インポートしようとしたため、Pythonはインポートできないことを認識し、ImportErrorをスローします。d.pyddd

ステップ4は、パッケージ内のファイルを直接実行したため、ここでは一種の異常です。これは、通常の方法ではありません。モジュールのインポートがモジュールの直接実行と異なる理由の説明については、この質問を参照してください。代わりに(を使用して)インポート しようとすると、Pythonは循環性を1ステップ早く認識し、より単純なトレースバックを取得します。tfrom testpack import t

>>> from testpack import t
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    from testpack import t
  File "C:\Documents and Settings\BrenBarn\My Documents\Python\testpack\t.py", line 1, in <module>
    from testpack import d
  File "C:\Documents and Settings\BrenBarn\My Documents\Python\testpack\d.py", line 1, in <module>
    from testpack import t
ImportError: cannot import name t

ここでのエラーは、tをインポートできないことです。私がtをインポートするように言ったとき、それ自体がループバックしてtを再度インポートすることに気付いたので、それができないことを知っています。元の例では、t.pyが2回実行されていることに気づきませんでした。これは、1回目がメインスクリプトで、2回目がインポートであったため、もう1つの手順を実行して、dを再度インポートしようとしたためです。

さて、あなたがそうするとき、なぜこれは起こらないのimport code.dですか?答えは、インポートされたモジュールを実際に使用しようとしないからです。この場合、次のようになります(from code import tスクリプトとして実行するのではなく、使用したかのように説明します)。

  1. tのインポートを開始します。これを行うと、code.tまだインポートが完了していなくても、モジュールにインポート済みのマークが暫定的に付けられます。
  2. やらなければならないことがわかったimport code.dので、dを実行します。
  3. dでは、が見つかりますimport code.tが、code.tすでにインポート済みとしてマークされているため、再度インポートしようとはしません。
  4. dは実際に使用せずに終了したのでt、戻って読み込みを終了しtます。問題ない。

主な違いは、ここでは名前tdが互いに直接アクセスできないことです。これらはパッケージによって仲介されるcodeため、Pythonは、実際に使用されるまで、実際に「tが何であるかを決定する」ことを完了する必要はありません。を使用from code import tすると、値を変数に割り当てる必要があるためt、Pythonはそれが何であるかをすぐに知る必要があります。

あなたがd.pyこのように見えるようにすると、あなたは問題を見ることができます:

import code.t
print code.t

ここで、ステップ2の後、dの実行中に、実際には半分インポートされたモジュールtにアクセスしようとします。モジュールはまだ完全にインポートされていないため、パッケージにアタッチされていないため、これによりAttributeErrorが発生しますcode

code.t実行が終了するまで使用が行われなかった場合は問題ないことに注意してくださいd。これは次の場合に正常に機能しd.pyます:

import code.t
def f():
    print code.t

f後で電話することができ、それは機能します。code.tその理由は、実行が終了するまで使用する必要がなくd、dが実行を終了した後、戻ってtの実行を終了できるためです。

繰り返しになりますが、ストーリーの主な教訓は、循環インポートを使用しないことです。それはあらゆる種類の頭痛につながります。代わりに、両方のモジュールによってインポートされた3番目のモジュールに共通のコードを除外します。

于 2012-09-23T23:14:36.807 に答える
1
from abc import xyz

するのと同じです

xyz = __import__('abc').xyz

単にimport abcabc.xyzがなければ存在しないので(abc/__init__.py明示的なimportforが含まれていない限りxyz)、表示されるのは期待される動作です。

于 2012-09-24T00:17:47.320 に答える
0

問題はabc、事前定義された標準ライブラリモジュールであり、同じ名前のサブディレクトリを作成するだけでは、__init__.pyその事実は変わりません。__init__.pyファイルが含まれているフォルダの名前を別の名前、つまりに変更して、パッケージの名前を別の名前に変更します。そうすればdef、両方の形式がimportエラーなしで実行されます。

于 2012-09-24T07:10:13.827 に答える