LoginSignup
2
1

【備忘録】importlibを使用した動的なインポート

Last updated at Posted at 2023-10-02

事の発端

以前作成したPython形式のファイルをJSON形式のファイルに書き換えたいと思い立ち,

  1. 変換対象のファイルから変数(中身は数字,文字,リスト,None,ブーリアン等)をインポート
  2. インポートした変数を辞書型に変更
  3. JSON形式で保存

を行う変換コードをPythonで作成してみました.変換対象のPythonファイルが1つであれば,変換コードの文頭で静的にインポートして万事解決でしたが,当該のPythonファイルが複数存在していたため,変換コード内でfor文を使用して一つ一つ変換していく運びになりました.

ところが,文頭以外で別のPythonファイルをインポートする方法を知らなかったため,「importlib」というパッケージを使用して文中で動的にインポートするということにしました.

変換対象のファイルの例

このようなファイルが複数個存在しています.また,格納先は
/hoge/src/
内となっています.

/hoge/src/example.py
# 日付と番号
date = ["20230607", 3]
# 名前
name = "佐藤太郎"

# 項目_1
item_1 = 200
# 項目_2
item_2 = [["", 1], ["", 2], ["", 3]]
# 項目_3
item_3 = False
# 項目_4(場合によっては二重リストの可能性あり)
item_4 = None
item_4 = [["", 4], ["", 5], ["", 6]]

作成中の変換のコード(Python形式)の例

こちらのコードは
/hoge/
内に格納されています.for文を使用して対象ファイル一つ一つに対して動的なインポート作業とJSON形式への出力作業を行うようにしています.

/hoge/main.py
import os
import json
from importlib import import_module

# インポートするPythonファイルを格納しているディレクトリ
dir_src = "/hoge/src/"
# 保存先のディレクトリ
dir_out = "/hoge/json/"


# インポートするPythonファイル名を与えると,当該ファイル内の変数をインポートし,必要に応じて変数を処理するクラス
class FileReader:
    def __init__(self, name_src: str) -> None:
        """
        Import variables in the input python file

        Args:
            name_src (str): name of the source python file
        """
        # 拡張子を除去したPythonファイルの名前
        name_base = os.path.splitext(name_src)[0]
        # Pythonファイルのインポート
        python_file = import_module("src." + name_base)

        # 日付と番号
        self.date = python_file.date
        # 名前
        self.name = python_file.name
        # 項目_1
        self.number = python_file.item_1
        # 項目_2
        self.list = {
            "item_2-1": {
                "sort": python_file.item_2[0][0],
                "number": python_file.item_2[0][1],
            },
            "item_2-2": {
                "sort": python_file.item_2[1][0],
                "number": python_file.item_2[1][1],
            },
            "item_2-3": {
                "sort": python_file.item_2[2][0],
                "number": python_file.item_2[2][1],
            },
        }
        # 項目_3
        self.boolean = python_file.item_3
        # 項目_4
        if python_file.item_4 == None:
            # Noneであれば変更なし
            self.none = python_file.item_4
        else:
            # 二重リストであれば辞書型に変更
            self.none = {}
            for i in range(0, len(python_file.item_4)):
                self.none[python_file.item_4[i][0]] = python_file.item_4[i][1]


for file in os.listdir(dir_src):
    inp = FileReader(name_src=file)
    # インポートしたデータを辞書型へ変更
    out = {
        "general": {"date": inp.date[0], "trial": inp.date[1], "name": inp.name},
        "items": {
            "item_1": inp.number,
            "item_2": inp.list,
            "item_3": inp.boolean,
            "item_4": inp.none,
        },
    }
    # JSON形式で出力
    json_name = inp.date[0] + "_" + str(inp.date[1]).zfill(2) + ".json"
    json_file = os.path.join(dir_out, json_name)
    with open(json_file, "w") as f:
        json.dump(out, f, indent=2, ensure_ascii=False)

結果

上手く変換できました.

/hoge/json/20230607_03.json
{
  "general": {
    "date": "20230607",
    "trial": 3,
    "name": "佐藤太郎"
  },
  "items": {
    "item_1": 200,
    "item_2": {
      "item_2-1": {
        "sort": "松",
        "number": 1
      },
      "item_2-2": {
        "sort": "竹",
        "number": 2
      },
      "item_2-3": {
        "sort": "梅",
        "number": 3
      }
    },
    "item_3": false,
    "item_4": {
      "序": 4,
      "破": 5,
      "急": 6
    }
  }
}
2
1
0

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
2
1