import の仕組みについて真面目に知りたい.
以下のようなディレクトリ構成を考える.
.
+- aa
+- __init__.py
+- a.py
+- b.py
+- bb.py
ファイルの中身は以下の通り. val
という変数をただ宣言してるだけだが, aa/b.py
だけ import
をしている.
cat aa/__init__.py
val = "init"
cat aa/a.py
val = "aa/a"
cat aa/b.py
import aa.a
import bb
val = "aa/b"
cat bb.py
val = "bb"
REPLを立ち上げて以下を実行する.
In [1]: import aa.a
In [2]: aa.a.val
Out[2]: 'aa/a'
In [3]: aa.val
Out[3]: 'init'
In [4]: aa.b.val
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-6eae9e67d772> in <module>()
----> 1 aa.b.val
AttributeError: module 'aa' has no attribute 'b'
すなわち aa.a
を import
をすれば aa.a
以下に宣言されたものを見ることが出来る. また aa.*
を import
すると上に遡って見つかる __init__.py
も自動的に import
されるため aa.val
を見ることが出来る. aa.b
は今は関係がないので見ることが出来ない.
次に REPL を再起動して次を実行する.
In [1]: import aa.b
In [2]: aa.b.val
Out[2]: 'aa/b'
In [3]: aa.val
Out[3]: 'init'
In [4]: aa.a.val
Out[4]: 'aa/a'
In [5]: bb.val
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-6-1d86821e907f> in <module>()
----> 1 bb.val
NameError: name 'bb' is not defined
今度は aa.b
を import
すれば、やはり aa.b
以下と aa.__init__
以下が見える. 先ほどと事情が異なるのは aa.a
は今回は REPL では import
していないのに見えていること. 原因として考えられるのはもちろん、 aa/b.py
の中で import aa.a
としていることしかない. 中で import
したものが REPL レベルにまで影響を及ぼすというのは過激な気がする. 更に混乱させるのは、同様に import bb
もしていたのに関わらず、こちらは REPL からは見えないことだ.
予想: 同じパッケージの
import
はトップレベルにまで影響する.