web-dev-qa-db-ja.com

2つのPythonモジュールは互いのコンテンツを必要とします-それは機能しますか?

私は、次の行を持つボトルWebサーバーモジュールを持っています。

from foobar.formtools import auto_process_form_insert

そしてその foobar.formtoolsモジュールには次の行が含まれます。

from foobar.webserver import redirect, redirect_back

もちろん、どちらも次のエラーになります(それぞれ):

ImportError:名前auto_process_form_insertをインポートできません
ImportError:名前リダイレクトをインポートできません

Python 2つのモジュールは相互にインポートできず、すべてのモジュールのインポートは本質的に階層的である必要がありますか、それとも何か間違っているのですか?これらすべての素敵な関数を新しいモジュールに配置しますか?

53
Hubro

モジュールcan相互に周期的にインポートしますが、キャッチがあります。単純な場合、importステートメントをファイルの最後に移動するか、from構文を使用しないことで機能します。

これが機能する理由は次のとおりです。

モジュールをインポートすると、Pythonは最初に_sys.modules_をチェックします。そこにある場合は、そこからインポートするだけです。存在しない場合、通常の方法でインポートしようとします。基本的に、ファイルを見つけて、その中のものを実行します。

モジュールを実行すると、モジュールの内容が読み込まれます。たとえば、_example_opener_というクリエイティブな名前のこのモジュールがあるとします。

_import webbrowser

def open_example():
    webbrowser.open('http://www.example.com/')
_

最初は、モジュールは空です。次に、Pythonが実行されます。

_import webbrowser
_

その後、モジュールにはwebbrowserのみが含まれます。次に、Pythonがこれを実行します。

_def open_example():
    webbrowser.open('http://www.example.com/')
_

Pythonは_open_example_を作成します。これで、モジュールにはwebbrowserおよび_open_example_が含まれます。

webbrowserにこのコードが含まれているとしましょう:

_from example_opener import open_example

def open(url):
    print url
_

_example_opener_が最初にインポートされるとします。次のコードが実行されます:

_import webbrowser
_

webbrowserはまだインポートされていないため、Pythonはwebbrowserの内容を実行します。

_from example_opener import open_example
_

_example_opener_ hasはインポートされましたが、まだ完全には実行されていません。 Pythonは気にしません。 Pythonは、モジュールを_sys.modules_から引き出します。この時点では、_example_opener_はまだ空です。 _open_example_はまだ定義されておらず、webbrowserのインポートも完了していません。 Pythonは_open_example_で_example_opener_を見つけることができないため、失敗します。

webbrowserの末尾から_open_example_をインポートし、_example_opener_の末尾からwebbrowserをインポートした場合はどうなりますか? Pythonは、次のコードを実行して開始します。

_def open_example():
    webbrowser.open('http://www.example.com/')
_

webbrowserはまだ存在しませんが、_open_example_が呼び出されるまで関係ありません。現在、_example_opener_には_open_example_のみが含まれています。その後、次を実行します。

_import webbrowser
_

まだインポートされていないため、Pythonはwebbrowserを実行します。始まる:

_def open(url):
    print url
_

openを定義します。それから実行します:

_from example_opener import open_example
_

_example_opener_は_sys.modules_にあるため、それを使用します。 _example_opener_には_open_example_が含まれているため、成功します。 Pythonはwebbrowserのインポートを終了します。これで、webbrowserを_example_opener_からインポートできました。これが_example_opener_の最後のことなので、_example_opener_のインポートも完了し、成功します。

64
icktoofay

しないでくださいfrom ... import ...。ただimport ...およびモジュール名を使用してそのオブジェクトを参照します。

21
pyrospade