Pluginなどをあるディレクトリに格納していて、それをコード内で個別にファイル指定せず、そのディレクトリ内にある*.pyのファイルを全てimportする方法です。
以下のようなディレクトリ構成を想定します。
./loader.py
./plugins
./plugins/__init__.py
./plugins/a.py
./plugins/b.py
__init__.py
は空でOKです。a.py
とb.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>