1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Python: import文は一度しか実行されない

Last updated at Posted at 2023-09-03

はじめに

モンテカルロ・シミュレーションなど,ループを使って値を変化させながら計算処理を行うプログラムを書きたいときがあります.
その際,私はimportの役割を勘違いをしており,悩まされた事があったので記録しておきます.

importとは?

importはモジュール,ライブラリなど外部のファイルを読み込むときに使用します.
具体的に何をしているかは詳しく理解していないのですが,どうやらimportは読み込む際にファイルの中身を実行しているみたいです.
この記事を参照してみてください.
10分で分かるPythonのimport

importの勘違い

私が勘違いしていた事は,import ファイル名が処理される度に,ファイルの中身が毎回実行されていると思っていた点です.
実際は最初に処理されるimport ファイル名のみファイルの中身が実行され,初回以降のimport ファイル名はファイルを読み込むだけのようです.

これを勘違いしていると,どういうときに困るのか紹介します.

間違った具体例

ランダムな値を生成するファイルを5回実行するプログラムを作成したいと思います.

まずランダムな値を生成するファイル,test_call.pyを用意します.

test_call.py
import random
a = random.random() #ランダムな値を生成

そして上記のファイルを読み込んで5回実行するファイルtest.pyを用意します.
test.pytest_call.pyは同じディレクトリに作成します.

test.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.pydef 任意の関数名()を使って,ランダムな値を生成して出力するプログラムを定義する.
    test.py任意の関数名()を入力すれば出力出来る.

正しい具体例

先程のtest.pyを次のように書き換えて実行してみます.
ここではimportlibを使用してみます.

test.py
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が実行されている事が分かります.

1
0
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?