はじめに
モンテカルロ・シミュレーションなど,ループを使って値を変化させながら計算処理を行うプログラムを書きたいときがあります.
その際,私はimport
の役割を勘違いをしており,悩まされた事があったので記録しておきます.
importとは?
import
はモジュール,ライブラリなど外部のファイルを読み込むときに使用します.
具体的に何をしているかは詳しく理解していないのですが,どうやらimport
は読み込む際にファイルの中身を実行しているみたいです.
この記事を参照してみてください.
10分で分かるPythonのimport
importの勘違い
私が勘違いしていた事は,import ファイル名
が処理される度に,ファイルの中身が毎回実行されていると思っていた点です.
実際は最初に処理されるimport ファイル名
のみファイルの中身が実行され,初回以降のimport ファイル名
はファイルを読み込むだけのようです.
これを勘違いしていると,どういうときに困るのか紹介します.
間違った具体例
ランダムな値を生成するファイルを5回実行するプログラムを作成したいと思います.
まずランダムな値を生成するファイル,test_call.py
を用意します.
import random
a = random.random() #ランダムな値を生成
そして上記のファイルを読み込んで5回実行するファイルtest.py
を用意します.
test.py
とtest_call.py
は同じディレクトリに作成します.
for i in range(5): #5回繰り返す
print(str(i+1)+"回目:") #何回目のループか表示
import test_call #test_call.pyを読み込む
print(test_call.a) #生成された値aを出力する(確認用)
ファイル構成はこんな感じです.
test_folder
├─ test.py
├─ test_call.py
test.py
を実行すると結果はこうなりました.
1回目:
0.01207048120170262
2回目:
0.01207048120170262
3回目:
0.01207048120170262
4回目:
0.01207048120170262
5回目:
0.01207048120170262
5回test_call.py
を読み込んでも値a
は1回目から変化せずに,初回に生成した値0.01207048120170262
が維持されています.
これは1回目のループでしかtest_call.py
が実行されてない証拠です.
ではどうすればよかったのか?
5回ランダムな値を生成する結果を得るには,解決策は主に3つ考えられます.
-
動的インポート(Dynamic Import)を使う.
importlib
という便利な標準ライブラリがあり,importlib.reload()
で何度も実行出来る.
importlib.reload()
はモジュールをリロードするコマンドで,ファイルを再読み込みが出来るため,一度読み込んだ後に変更があった場合,変更を反映させることが出来る. -
subprocess
モジュールを使って.外部ファイルを実行する.
この記事を参照してみてください.
【subprocess】Pythonのコードの中で別のPythonプログラムを実行したいとき -
外部ファイルに関数としてプログラムを定義して,呼び出す.
test_call.py
でdef 任意の関数名()
を使って,ランダムな値を生成して出力するプログラムを定義する.
test.py
で任意の関数名()
を入力すれば出力出来る.
正しい具体例
先程のtest.py
を次のように書き換えて実行してみます.
ここではimportlib
を使用してみます.
import importlib, test_call
for i in range(5): #5回繰り返す
print(str(i+1)+"回目:") #何回目のループか表示
importlib.reload(test_call) #test_call.pyを読み込む
print(test_call.a) #生成された値aを出力する(確認用)
結果はこうなりました.
1回目:
0.12550873557544917
2回目:
0.7754000872698203
3回目:
0.8982510719027913
4回目:
0.931713339185291
5回目:
0.9614093168596568
毎回違う値が出力されているので,しっかりtest_call.py
が実行されている事が分かります.