1

Python は、循環インポートに陥る可能性のある状況を思いとどまらせることを知っています。しかし、循環インポートの状況で from-import が通常のインポートよりも恣意的に寛大でないように見える理由について、Python の内部構造を理解したいと思いました。

たとえば、次のコードはコンパイルされます。

# main.py
import CommonUtil

# commonutil.py
import util
class CommonUtil:
    # some code that uses util.Util
    pass

# util.py
import commonutil
class Util:
    # some code that uses commonutil.CommonUtil
    pass

ただし、このコードは次のことを行いません。

# main.py
import CommonUtil

# commonutil.py
import util
class CommonUtil:
    # some code that uses util.Util
    pass

# util.py
from commonutil import CommonUtil
class Util:
    # some code that uses CommonUtil
    pass

Traceback (most recent call last):
  File "main.py", line 1, in <module>
    import CommonUtil
  File "commonutil.py", line 1, in <module>
    import util
  File "util.py", line 1, in <module>
    from commonutil import CommonUtil
ImportError: cannot import name CommonUtil

すべてのインポートが完了する前に関連するクラスを使用しようとしない限り、コンパイラ エラーは発生しません。しかし、エイリアシングを行おうとすると失敗します。from-import が使用されている場合にのみ、このエラーが頭をもたげる原因となる Python の内部で何が起こっているのかを誰かが説明できますか? 第二に、これを回避する簡単な方法はありますか? (明らかな「共有コードを 3 番目のモジュールに引き出す」以外に、私はおそらくそうするでしょう。)

4

2 に答える 2

2

モジュールは上から順に実行されます。初めてインポートが表示されると、現在のモジュールの実行が中断され、他のモジュールをインポートできるようになります。他のモジュールが最初のモジュールをインポートしようとすると、現在部分的に実行されているモジュールへの参照が取得されます。他のモジュールのインポートの後に配置されたコードはまだ実行されていないため、その中に含まれる名前はまだ存在できません。

main.py

import a

a.py

var1 = 'foo'
import b
var2 = 'bar'

b.py

import a
print a.var1 # works
print a.var2 # fails

これを回避するには、実行が完了するまで、インポートされたモジュールの名前にアクセスしないようにします。

于 2011-09-29T01:45:45.560 に答える
1

何が起こっているのかについては、http://effbot.org/zone/import-confusion.htm#circular-importsを参照してください。

main.py ファイルを起動するとします。Python は最初に をロードしようとしますcommonutil。モジュールオブジェクトを作成し、それらの定義に遭遇すると、クラス、関数、およびグローバル変数で埋め始めます。最初のステートメントはインポートであるため、python はutilモジュールを作成し、入力を開始します。共通モジュールは存在しますが、空です。最初のバージョンでは、読み込み時に commonutil オブジェクトにアクセスしないので、すべて問題ありません。2 つ目では、現時点では存在しない commonutil の特定の変数を取得しようとしています。最初のバージョンのようなものを使っていたらf(commonutil.CommonUtil)、それもクラッシュしていたでしょう。

于 2011-09-29T01:51:48.663 に答える