回答:
を使用していfrom bar import a
ます。a
インポートモジュールのグローバルスコープ(またはインポートステートメントが発生するスコープ)のシンボルになります。
新しい値をに割り当てると、実際の値ではなく、a
どの値a
も変更するだけです。in を使用してbar.py
直接インポートしimport bar
、__init__.py
を設定して実験を行いますbar.a = 1
。このようにして、実際にこのコンテキストbar.__dict__['a']
での「本当の」値である変更を行いa
ます。
これは3つのレイヤーで少し複雑ですが、実際にから派生したと呼ばれるモジュールののbar.a = 1
値を変更します。これは、の値が変更されないので、見ている実際のファイルでの生活を。変更したい場合は設定できます。a
bar
__init__.py
a
foobar
foobar
bar.py
bar.bar.a
これはfrom foo import bar
、import
ステートメントの形式を使用する際の危険の1つですbar
。2つのシンボルに分割されます。1つはグローバルに表示され、内部foo
からは元の値を指し、別のシンボルはimport
ステートメントが実行されるスコープで表示されます。シンボルが指す場所を変更しても、それが指している値は変わりません。
この種のものはreload
、インタラクティブインタープリタからモジュールを作成しようとするときにキラーです。
bar.bar.a
ほとんどのユースケースでは、このアプローチでもあまり役に立たないようです。自分自身(またはコードを使用する他のユーザー)を混乱させることになるので、コンパイルまたはモジュールのロードとランタイムの割り当てを混在させるのはおそらく弱い考えです。特に、Pythonが間違いなくそうであるように、それについて多少一貫性のない動作をする言語では。
この質問の難しさの一つの原因は、あなたが名前のプログラムを持っていることですbar/bar.py
:import bar
輸入のいずれかbar/__init__.py
またはbar/bar.py
それを追跡するために少し面倒になりれ、行われている場所に応じて、a
ですbar.a
。
以下にその仕組みを示します。
何が起こるかを理解するための鍵は__init__.py
、
from bar import a
実際には次のようなことをします
a = bar.a
# … where bar = bar/bar.py (as if bar were imported locally from __init__.py)
新しい変数を定義します(bar/__init__.py:a
必要に応じて)。したがって、from bar import a
in __init__.py
はbar/__init__.py:a
元のbar.py:a
オブジェクト(None
)に名前をバインドします。あなたがすることができる理由はここにあるfrom bar import a as a2
中__init__.py
:この場合には、あなたが両方を持っていることは明らかであるbar/bar.py:a
と明確な変数名はbar/__init__.py:a2
(あなたのケースでは、2つの変数の名前はちょうど両方のことが起こるa
が、異なる名前空間で、彼らはまだ生きて:中__init__.py
、それらはbar.a
ありますa
)。
今、あなたがするとき
import bar
print bar.a
変数にアクセスしていますbar/__init__.py:a
(をimport bar
インポートしているためbar/__init__.py
)。これは、(1に)変更する変数です。変数の内容には触れていませんbar/bar.py:a
。だからあなたがその後するとき
bar.foobar()
あなたはを呼び出してbar/bar.py:foobar()
、a
からbar/bar.py
まだ変数にアクセスしますNone
(foobar()
定義されている場合、変数名をバインドするので、他のモジュールで定義されている他の変数a
でbar.py
はbar.py:a
なく、in a
です- a
インポートされたすべてのモジュールに多くの変数がある可能性があるため))。したがって、最後のNone
出力です。
結論:モジュールを持たないことでimport bar
、の曖昧さを回避するのが最善です(ディレクトリをすでにパッケージにしているため、でインポートすることもできます)。bar/bar.py
bar.__init__.py
bar/
import bar
言い換えると、この誤解は非常に簡単に起こります。 Python言語リファレンスでこっそりと定義されています:シンボルの代わりにオブジェクトを使用します。Python言語リファレンスを使用すると、これがより明確になり、まばらにならないようにすることをお勧めします。
from
フォームはバインドモジュール名はありません:それは識別子のリストを通過するには、モジュールでそれらの一つ一つを見上げステップ(1)で見つかった、とのローカル名前空間に名前をバインドするオブジェクトこのようにして求めました。
しかしながら:
インポートするときは、インポートされたシンボルの現在の値をインポートし、定義どおりにネームスペースに追加します。 参照をインポートするのではなく、値を効果的にインポートします。
したがって、の更新された値を取得するにはi
、そのシンボルへの参照を保持する変数をインポートする必要があります。
つまり、インポートはimport
、JAVAのexternal
C、C / C ++の宣言、またはuse
PERLの句とは異なります。
むしろ、Pythonでの次のステートメント:
from some_other_module import a as x
以上あるような K&R Cに以下のコード:
extern int a; /* import from the EXTERN file */
int x = a;
(注意:Pythonの場合、「a」と「x」は基本的に実際の値への参照です。INTをコピーするのではなく、参照アドレスをコピーします)
import
名前空間/スコープは常に適切に分離され、予期しない方法で相互に干渉しないため、Pythonの方がJavaよりはるかにクリーンであることがわかります。このように:オブジェクトのバインディングをネームスペース内の名前に変更(読み取り:モジュールのグローバルプロパティに何かを割り当てる)しても、Pythonの他のネームスペース(読み取り:インポートされた参照)に影響を与えることはありません。しかし、Javaなどではそうです。Pythonではインポートされたものを理解するだけでよく、Javaでは、インポートされた値が後で変更される場合に備えて他のモジュールも理解する必要があります。