自己动手实现python插件框架(python plugin framework 附源码)
By:Roy.LiuLast updated:2012-11-24
python做为一个动态语言,可以很方便的调用,在程序需要的时候去调用,而且是动态调用的。这为程序开发带来了很大的方便。很多程序都采用了插件式开发,因为方便扩展。在python里,有什么好方法实现插件了,我实现了一个简单的插件:
1. 定义一个插件目录,所有插件都放在这个目录里面。
2. 定义插件要实现的基类,主要是为了插件管理分类方便,python作为动态语言,基类,接口没有太大的意义,因为随时可以扩展。
3. 定义插件管理器,用插件管理器去load 插件
4. 测试调用插件
整个程序目录结构如下(我用pydev做的):
iPlugin 是所有插件必须实现的接口,而且里面的name 属性必须定义,插件管理器,根据这个name 去调用插件.
插件管理器的实现
因为可能有很多种方式管理插件,不同的插件管理器,实现方式不一样,所以定义个插件管理器的基类,各种具体的插件管理器是实现这个基类,比如这里实现了一个 基于目录结构去查找插件的 DirectoryPluginManager
在plugin 目录下 写自己的插件,注意必须实现Plugin 接口,并且必须写name属性
调用插件
通过插件管理器去调用插件,用你自己需要的插件管理器去调用,我这里只实现了一个基于目录结构的。
你会发现,DirectoryPluginManager 找到了名字为 firstPlugin 插件,并成功执行了调用,值得注意的是,在所有的 实现的插件里面,我都加入了一个 __all__属性 暴露公开的类,同时在 pluginManager 里面也用到这个属性。
源代码下载:
点击下载此文件
1. 定义一个插件目录,所有插件都放在这个目录里面。
2. 定义插件要实现的基类,主要是为了插件管理分类方便,python作为动态语言,基类,接口没有太大的意义,因为随时可以扩展。
3. 定义插件管理器,用插件管理器去load 插件
4. 测试调用插件
整个程序目录结构如下(我用pydev做的):
iPlugin 是所有插件必须实现的接口,而且里面的name 属性必须定义,插件管理器,根据这个name 去调用插件.
#coding:utf-8 class Plugin(object): """ 定义一个接口,其他 插件必须实现这个接口,name 属性必须赋值 """ name = '' description = '' version = '' def __init__(self): pass def executeFun(self): pass
插件管理器的实现
因为可能有很多种方式管理插件,不同的插件管理器,实现方式不一样,所以定义个插件管理器的基类,各种具体的插件管理器是实现这个基类,比如这里实现了一个 基于目录结构去查找插件的 DirectoryPluginManager
#coding:utf-8 from iPlugin import Plugin from imp import find_module,load_module,acquire_lock,release_lock import os import sys class PluginManager(object): """Base class for plugin managers. Does not implement loadPlugins, so it may only be used with a static list of plugins. """ name = "base" def __init__(self, plugins=(), config={}): self.__plugins = [] if plugins: self.addPlugins(plugins) def __iter__(self): return iter(self.plugins) def addPlugin(self, plug): print 'PluginManager add plugin:',plug self.__plugins.append(plug) def addPlugins(self, plugins): for plug in plugins: self.addPlugin(plug) def delPlugin(self, plug): if plug in self.__plugins: self.__plugins.remove(plug) def delPlugins(self, plugins): for plug in plugins: self.delPlugin(plug) def getPlugins(self,name=None): plugins = [] print 'self.__plugins:',self.plugins for plugin in self.__plugins: print 'plugin.name',plugin.name if (name is None or plugin.name == name): plugins.append(plugin) return plugins def _loadPlugin(self, plug): loaded = False print '******PluginManager _loadPlugin ,',self.plugins for p in self.plugins: if p.name == plug.name: loaded = True break if not loaded: self.addPlugin(plug) print "%s: loaded plugin %s " % (self.name, plug.name) def loadPlugins(self): pass def _get_plugins(self): return self.__plugins def _set_plugins(self, plugins): self.__plugins = [] self.addPlugins(plugins) plugins = property(_get_plugins, _set_plugins, None, """Access the list of plugins managed by this plugin manager""") class DirectoryPluginManager(PluginManager): """Plugin manager that loads plugins from plugin directories. """ name = "directory" def __init__(self, plugins=(), config={}): default_directory = os.path.join(os.path.dirname(__file__),"plugins") self.directories = config.get("directories", (default_directory,)) print '========DirectoryPlugManager========',plugins PluginManager.__init__(self, plugins, config) def loadPlugins(self): """Load plugins by iterating files in plugin directories. """ plugins = [] print '********Directory directories:',self.directories for dir in self.directories: try: for f in os.listdir(dir): if f.endswith(".py") and f != "__init__.py": plugins.append((f[:-3], dir)) except OSError: print "Failed to access: %s" % dir continue fh = None mod = None print '********Directory all plugins:',plugins for (name, dir) in plugins: try: acquire_lock() fh, filename, desc = find_module(name, [dir]) print '********Directory fh,filename,desc:',fh,filename,desc,name old = sys.modules.get(name) if old is not None: # make sure we get a fresh copy of anything we are trying # to load from a new path del sys.modules[name] mod = load_module(name, fh, filename, desc) finally: if fh: fh.close() release_lock() if hasattr(mod, "__all__"): print '********Directory mod __all__:',mod.__all__ attrs = [getattr(mod, x) for x in mod.__all__] print '********Directory attrs:',attrs for plug in attrs: if not issubclass(plug, Plugin): continue self._loadPlugin(plug())
在plugin 目录下 写自己的插件,注意必须实现Plugin 接口,并且必须写name属性
#coding:utf-8 import sys sys.path.append('../') from iPlugin import Plugin __all__ = ["FirstPlugin"] class FirstPlugin(Plugin): name = "firstPlugin" version = '0.0.1' def __init__(self): Plugin.__init__(self) def scan(self, config={}): return "first plugin" def execFun(self): return "exec function"
调用插件
通过插件管理器去调用插件,用你自己需要的插件管理器去调用,我这里只实现了一个基于目录结构的。
#coding:utf-8 from pluginManager import DirectoryPluginManager import os if __name__=='__main__': plugin_manager = DirectoryPluginManager() plugin_manager.loadPlugins() plugins = plugin_manager.getPlugins("firstPlugin") print "**"*30 print plugins[0].execFun()
你会发现,DirectoryPluginManager 找到了名字为 firstPlugin 插件,并成功执行了调用,值得注意的是,在所有的 实现的插件里面,我都加入了一个 __all__属性 暴露公开的类,同时在 pluginManager 里面也用到这个属性。
源代码下载:
点击下载此文件
From:一号门
Previous:java 数组排序的简单方法
COMMENTS