插件架构-插件管理器与从插件导入检查* [英] Plugin architecture - Plugin Manager vs inspecting from plugins import *

查看:106
本文介绍了插件架构-插件管理器与从插件导入检查*的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在编写一个应用程序,允许用户通过插件"类型的体系结构对其进行扩展.他们可以根据我提供的BaseClass对象编写其他python类,并且这些类会根据各种应用程序信号进行加载.在启动应用程序之前,未知作为插件加载的类的确切数目和名称,但在启动时仅加载一次.

I'm currently writing an application which allows the user to extend it via a 'plugin' type architecture. They can write additional python classes based on a BaseClass object I provide, and these are loaded against various application signals. The exact number and names of the classes loaded as plugins is unknown before the application is started, but are only loaded once at startup.

在研究解决此问题的最佳方法的过程中,我提出了两种常见的解决方案.

During my research into the best way to tackle this I've come up with two common solutions.

选项1-使用imp,pkgutil等进行滚动.
例如,参见此答案这个.

Option 1 - Roll your own using imp, pkgutil, etc.
See for instance, this answer or this one.

选项2-使用插件管理器库
随机挑选一对情侣

Option 2 - Use a plugin manager library
Randomly picking a couple

  • straight.plugin
  • yapsy
  • this approach

我的问题是-在必须重新启动应用程序才能加载新插件的前提下-上述方法相对于此一个,例如:

My question is - on the proviso that the application must be restarted in order to load new plugins - is there any benefit of the above methods over something inspired from this SO answer and this one such as:

import inspect
import sys
import my_plugins

def predicate(c):
    # filter to classes
    return inspect.isclass(c)

def load_plugins():
    for name, obj in inspect.getmembers(sys.modules['my_plugins'], predicate):
        obj.register_signals()

与上述方法相比,此方法是否有任何缺点? (除了所有的插件必须在同一个文件中)谢谢!

Are there any disadvantages to this approach compared to the ones above? (other than all the plugins must be in the same file) Thanks!

编辑
评论要求提供更多信息...我唯一想添加的就是插件使用 blinker blinker 库,以提供他们订阅的信号.每个插件可以订阅不同类型的不同信号,因此必须具有自己的特定注册"方法.

EDIT
Comments request further information... the only additional thing I can think to add is that the plugins use the blinker library to provide signals that they subscribe to. Each plugin may subscribe to different signals of different types and hence must have its own specific "register" method.

推荐答案

元类方法对于Python< 3.6(请参阅@quasoft对Python 3.6及更高版本的回答).它非常简单,并且可以自动对任何导入的模块起作用.此外,可以很轻松地将复杂的逻辑应用于插件注册.它要求:

The metaclass approach is useful for this issue in Python < 3.6 (see @quasoft's answer for Python 3.6+). It is very simple and acts automatically on any imported module. In addition, complex logic can be applied to plugin registration with very little effort. It requires:

元类方法的工作方式如下:

The metaclass approach works like the following:

1)定义了一个自定义的PluginMount元类,该元类维护所有插件的列表

1) A custom PluginMount metaclass is defined which maintains a list of all plugins

2)定义了一个Plugin类,该类将PluginMount设置为其元类

2) A Plugin class is defined which sets PluginMount as its metaclass

3)导入从Plugin派生的对象-例如MyPlugin时,它将触发元类上的__init__方法.这将注册插件并执行任何特定于应用程序的逻辑和事件订阅.

3) When an object deriving from Plugin - for instance MyPlugin is imported, it triggers the __init__ method on the metaclass. This registers the plugin and performs any application specific logic and event subscription.

或者,如果将PluginMount.__init__逻辑放在PluginMount.__new__中,则在创建Plugin派生类的新实例时会调用它.

Alternatively if you put the PluginMount.__init__ logic in PluginMount.__new__ it is called whenver a new instance of a Plugin derived class is created.

class PluginMount(type):
    """
    A plugin mount point derived from:
        http://martyalchin.com/2008/jan/10/simple-plugin-framework/
    Acts as a metaclass which creates anything inheriting from Plugin
    """

    def __init__(cls, name, bases, attrs):
        """Called when a Plugin derived class is imported"""

        if not hasattr(cls, 'plugins'):
            # Called when the metaclass is first instantiated
            cls.plugins = []
        else:
            # Called when a plugin class is imported
            cls.register_plugin(cls)

    def register_plugin(cls, plugin):
        """Add the plugin to the plugin list and perform any registration logic"""

        # create a plugin instance and store it
        # optionally you could just store the plugin class and lazily instantiate
        instance = plugin()

        # save the plugin reference
        cls.plugins.append(instance)

        # apply plugin logic - in this case connect the plugin to blinker signals
        # this must be defined in the derived class
        instance.register_signals()

然后是一个基本的插件类,如下所示:

Then a base plugin class which looks like:

class Plugin(object):
    """A plugin which must provide a register_signals() method"""
    __metaclass__ = PluginMount

最后,实际的插件类如下所示:

Finally, an actual plugin class would look like the following:

class MyPlugin(Plugin):
    def register_signals(self):
        print "Class created and registering signals"

    def other_plugin_stuff(self):
        print "I can do other plugin stuff"

可以从已导入Plugin的任何python模块访问插件:

Plugins can be accessed from any python module that has imported Plugin:

for plugin in Plugin.plugins:
    plugin.other_plugin_stuff()

请参见完整的示例

这篇关于插件架构-插件管理器与从插件导入检查*的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆