聞かれたときに間違えて答えて恥しかったのでメモしておく。
事の発端はscipy.specialが参照できなかったという話。
つまりこういうことだった。
import scipy as sci
sci.special # AttributeError
import scipy.special
scipy.special # Not error
上のパターンでエラーが起きるとは思ってなかったので面喰らった。
調べてみた。
下位モジュール
Pythonではあるモジュールの内側に別のモジュールをネストさせられる。
いままで上位のモジュールをインポートしたら下位のモジュールも参照できるのが当然だと思っていたけどどうも違うらしい。
テストするために簡単なモジュールを作成した。
テスト
こんな感じの構成になった。
使ったのはpython3.6.1。
test.py
test1/
__init__.py
test2/
__init__.py
test.py
import test1
print(dir(test1))
# callable
test1.func_in_test1()
# not callable
try:
test1.test2.func_in_test2()
except AttributeError as e:
print("Error!")
import test1.test2
print(dir(test1))
# callable here
test1.test2.func_in_test2()
test1/__init__.py
def func_in_test1():
print('test1')
return
test2/__init__.py
def func_in_test2():
print('test2')
return
test.pyを動かしてテストしてみた、出力は以下のようになった。
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'func_in_test1']
test1
Error!
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'func_in_test1', 'test2']
test2
下位モジュールの関数を見れていないし、そもそも下位モジュール自体が名前空間(で合っているんだろうか?)に含まれていない。
下位のモジュールを使う場合には明示的にインポートしないといけないらしい。
おそらく、外部には公開しない内部向けのモジュールのためにそうなっているのだと思う。
ちなみに、test1/__init.py__
内でインポートしたモジュールは問題なく参照できる。
知らんかった。