LoginSignup
3
4

More than 5 years have passed since last update.

Pythonで指定したディレクトリ内の*.pyに含まれるクラスを一括して読み込む方法

Posted at

Pluginなどをあるディレクトリに格納していて、それをコード内で個別にファイル指定せず、そのディレクトリ内にある*.pyのファイルを全てimportする方法です。

以下のようなディレクトリ構成を想定します。

./loader.py
./plugins
./plugins/__init__.py
./plugins/a.py
./plugins/b.py

__init__.pyは空でOKです。a.pyb.pyはとりあえずこんな感じ。

a.py
#!/usr/bin/env python
# coding: utf-8

class Plugin1:
    ''' plugin1 '''

class Plugin2:
    ''' plugin2 '''
b.py
#!/usr/bin/env python
# coding: utf-8

class Plugin3:
    ''' plugin3 '''

loader.py を以下のように書きます。

loader.py
#!/usr/bin/env python
# coding: utf-8

import os
import inspect
import importlib
import glob

def load_classes(dname):
    class_list = []

    # *.pyを読み込む
    for fpath in glob.glob(os.path.join(dname, '*.py')):
        # 拡張子を除去&ファイルパスのセパレータ (Unix系なら'/') を '.' に置き換え
        cpath = os.path.splitext(fpath)[0].replace(os.path.sep, '.')
        # モジュールとして読み込み
        mod = importlib.import_module(cpath)
        # 読み込んだモジュールに含まれるクラスを呼び出す
        for cls_name, cls in inspect.getmembers(mod, inspect.isclass):
            # (ディレクトリパス含むクラス名, クラス本体) という形式で格納
            class_list.append(('{0}.{1}'.format(cpath, cls_name), cls))

    return class_list


import pprint
clist = load_classes('plugins')
pprint.pprint(clist)

実行結果は以下の通り。

$ ./loader.py
[('plugins.a.Plugin1', <class plugins.a.Plugin1 at 0x10d2538d8>),
 ('plugins.a.Plugin2', <class plugins.a.Plugin2 at 0x10d253940>),
 ('plugins.b.Plugin3', <class plugins.b.Plugin3 at 0x10d2539a8>)]

リストの2つ目の要素がクラス本体なので、これを使ってインスタンスを生成できます。

c = clist[0][1]()
print c
# <plugins.a.Plugin1 instance at 0x107195d40>
3
4
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
3
4