Pluginシステムの実装
ちょっとPlugin的なものを実装しようとしてたら行き着いた。
http://lucumr.pocoo.org/2006/7/3/python-plugin-system
importする仕組みはよくあるのでわかるんだけど。
読み込んだモジュールからPluginクラスを抽出するスマートな方法が書いてあったので紹介しておく。
class Plugin(object): pass class MyPlugin1(Plugin): pass class MyPlugin2(Plugin): pass Plugin.__subclasses__()
__subclasses__()で一発でとれる。
baseのtuple(スーパークラスのリスト)はよく使うんだけどsubclassも取れるのは忘れてた。
で自分でも書いてみた。
plugin.py
import sys import os import os.path as path default_plugin_path = path.join(path.abspath(path.curdir), 'plugins') class Plugin(object): pass def default_plugin(): default = path.join(path.dirname(__file__), 'plugins') return list_module(default) def list_module(dir): if path.isdir(dir): return [path.splitext(file)[0] for file in os.listdir(dir) if not file.startswith('__')] return [] def init_plugins(cfg): sys.path.insert(0, path.join(path.dirname(path.abspath(__file__)), 'plugins')) plugin_path = cfg.get('plugin_path', default_plugin_path) plugins = cfg.get('plugins', list_module(plugin_path)) if not plugin_path in sys.path: sys.path.insert(0, plugin_path) plugins.extend(default_plugin()) import_plugins(plugins) def import_plugins(plugins): for plugin in plugins: __import__(plugin, None, None, ['']) def find_plugins(): return Plugin.__subclasses__() def load_plugins(cfg={}): init_plugins(cfg) return find_plugins()
自分自身がおいてあるディレクトリ内の'plugins'ディレクトリと実行時のカレントディレクトリ内の'plugins'を読み込む。
(configで一部置き換えれる)
使うときはload_pluginsでクラスのリストを受け取ってインスタンス化する
for plugin in load_plugins(): p = plugin()
まあホントはインスタンス化、カテゴリ化、シングルトンもpluginモジュールでやってもいいんだけど手抜きで。