ふと「あれ、どうなってるんだっけ」と思うことがあったので実験してみる。
import_test.py
import time print("aaa") def hoge(): print("hoge") print("bbb") def fuga(): print("fuga") for i in range(1, 4): print(i) time.sleep(1)
普通に実行すると、
$ python import_test.py aaa bbb 1 2 3
当然こうなる。1,2,3は1秒おきに出力される。
pythonではモジュールをimportした場合、モジュール内のコードがすべて実行される。また、一度読み込まれたモジュールは特別なことをしなければリロードされない。
>>> import import_test aaa bbb 1 2 3 >>> from import_test import hoge >>>
一度対話的インタプリタを落として再起動し、素の状態でfrom import_test import hogeとしても、ぜんぶ実行されるのだろうか?
>>> from import_test import hoge aaa bbb 1 2 3 >>> hoge() hoge
された。そしてこの状態でfrom import_test import fugaとしても、すでにimport_test.pyがまるごと実行されているため、もう一度aaaからprintされることはなかった。
納得が行くような気も、ちょっと行かないような気もするけど、とりあえずドキュメントを見に行ってみた。すると興味深い記述があった。
import 文は 2 つの処理を連続して行っています; ある名前のモジュールを探し、その検索結果をローカルスコープの名前に束縛します。
5. インポートシステム — Python 3.6.5 ドキュメント
要するに、
- モジュールのロードは原則最初の1回だけ。ロードの単位はモジュール(最も一般的なのは.pyのファイル)であり、fromを使おうと一部の関数だけロードする、といったことはできない。モジュール内はすべて実行される。
- 2回目以降では、1回目でロードされたモジュールオブジェクトの構成要素に対するimport元の名前空間での名前束縛が発生するだけ。
と考えれば良い、ということかな。だとするとそれなりに納得はできる。
なお、この様子はsys.modulesで確認できるとドキュメントに書いてあった。
>>> import sys >>> "import_test" in sys.modules False >>> from import_test import hoge aaa bbb 1 2 3 >>> "import_test" in sys.modules True >>> sys.modules["import_test"] <module 'import_test' from '/.../import_test.py'> # ディレクトリ名略 >>> sys.modules["import_test"].fuga() fuga
なるほど、こうやってまるごとimportされている訳だね。