3

SO での再インポートに関する質問と回答はたくさんありますが、その背後にあるメカニズムを知らなければ、すべて直感に反するように思えます。

モジュールをインポートし、内容を変更してから再度インポートしようとすると、2 回目のインポートは効果がないことがわかります。

>>> import foo    # foo.py contains: bar = 'original'
>>> print foo.bar
original
>>> # edit foo.py and change to: bar = 'changed'
>>> import foo
>>> print foo.bar
original

私が発見したとき、私はとても幸せなキャンピングカーでしたreload

>>> reload(foo)
>>> print foo.bar
changed

ただし、モジュール自体をインポートせずにモジュールからアイテムをインポートする場合、簡単な解決策はありません。

>>> from foo import baz
>>> print baz
original
>>> # change foo.py from baz = 'original' to baz = 'changed'
>>> from foo import baz
>>> print baz
original
>>> reload(foo)
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    reload(foo)
NameError: name 'foo' is not defined

import新しいステートメントを与えたときに、Python がインポートされた項目を更新しないのはなぜですか?

4

2 に答える 2

11

モジュールをインポートすると、 にキャッシュされsys.modulesます。同じセッション内で同じモジュールを再度インポートしようとすると、そこに含まれている既存のモジュールが返されるだけです。これにより、モジュールが複数の場所からインポートされるときの全体的なエクスペリエンスが高速化されます。また、毎回同じモジュールが返されるため、モジュールはすべてのインポート間で共有される独自のオブジェクトを持つことができます。

前述のようreloadに、モジュール全体を再インポートするために使用できます。これでも確実ではないため、注意事項についてはドキュメントを確認してください。

モジュールから特定の項目をインポートすると、モジュール全体が上記のようにインポートされ、要求したオブジェクトが名前空間に配置されます。reloadこれらのオブジェクトはモジュールではなく、モジュール自体への参照を受け取っていないため、機能しません。回避策は、モジュールへの参照を取得し、再読み込みしてから再インポートすることです。

>>> from foo import baz
>>> print baz
original
>>> # change foo.py from baz = 'original' to baz = 'changed'
>>> import foo
>>> reload(foo)
>>> from foo import baz
>>> print baz
changed
于 2012-07-23T18:56:24.047 に答える
2

「理由」の簡単な説明は、インポート ステートメントには 2 つの操作が含まれるということです。つまり、モジュールのロード (つまり、モジュール内のコードの実行) と、インポートするモジュールの名前空間への名前のインポートです。再インポートは、2 番目の操作をやり直すだけです。その理由は、最初の操作は、計算およびメモリ リソースの点でコストがかかる可能性があるためです。

reload最初の操作をやり直す方法として提供されていますが、ご覧のとおり、モジュール名が必要です。ただし、モジュール全体がロードfrom foo import barされないという考えに惑わされないでください。します。すべてのモジュールのコードが実行されます。明示的にインポートした名前 (例: ) を参照するだけです。このため、モジュールをインポートする場合としない場合の実際の違いはほとんどありません。唯一の違いは名前空間の問題です。したがって、モジュールをリロードしたい場合は、先に進んで実行してください。必要に応じて、これを実行してインポートした名前を更新できます。barfooimport foo

import foo
from foo import bar
# later...
reload(foo)
from foo import bar

個々の名前を再インポートできないもう 1 つの理由があります。それは、Python には参照されるオブジェクトを変更する方法がないためです。名前の再バインドのみが可能です。これを行うとします:

from foo import bar
newBar = bar
from foo import bar

2 回目のインポートで実際に bar の値が更新されたとしても、newBar の値を更新することはできません。これは、foo も bar も、bar を参照するために追加の名前を作成したことを知る方法がないためです。個々の名前の再結合を避けることで、この罠に陥るのを防ぐことができます。再インポートすると名前が更新されると人々が考えると、オブジェクトが更新されないことを忘れがちです。

于 2012-07-23T19:17:37.503 に答える