基于类的扩展/插件库
extend_me的Python项目详细描述
扩展我-基于类的扩展/插件库
此模块提供应用程序的扩展机制 基于"通过继承扩展"。我的意思是 能够简单地定义应用程序对象的新扩展 通过对应用程序的可扩展类进行子类化。
例如,我们有一个带"worker"类的应用程序 使可扩展(允许第三方模块扩展或 改变它的行为)。思维狭隘,工作很多 要做到的是,对加载、登记的推动机制, 结束启用扩展,使用大量粘合代码,必须定义 一些连接扩展和主应用程序的入口点。但为什么不呢? 假设"worker"的任何子类 扩展它?这个模块提供了 有两种方式:
- 显式(通过直接使用元类 可扩展类型 )
- 当你用这种方法时,你将拥有单独的基类 由扩展类和类getter子类 它将基于所有定义的扩展来构造类 使用多个inhertance
工作原理
元类( extensibletype )跟踪类it的所有子类 应用于,并提供基于 基类的子类,因此使用 子类。因此正确类的生成是一个独立的过程 应该在需要可扩展类的地方使用它。
为了简化这个类,实现了可扩展类。它重新定义了 方法自动创建正确类的实例 (继承自基类及其所有扩展的类)
示例
可扩展类型
一开始我们应该创建一个自动 获取所有扩展的所有信息,并应用此元类 要分类,我们希望启用扩展:
>>> import six # Used for Python 2/3 compatability >>> mc = ExtensibleType._("Object") >>> @six.add_metaclass(mc) ... class Object(object): ... pass
不是可扩展类型的方法。此方法用于创建元类 对于特定对象。它接收一个参数字符串,该字符串将用作 此元类生成的类的名称
接下来我们可以定义这个类的扩展。很简单。 只是子类以前定义的类:
>>> class ObjectExtension(Object): ... cool_attribute = 1 ... def method1(self): ... return "Test"
所以…现在我们有基类和扩展。这就是 核心魔法出现。在automaticaly开始时创建的元类 收集基类的所有子类。所以现在可以创造新的 类是子类使用多重继承的基类的所有子类的。 元类mc会帮你做到的:
>>> cls = mc.get_class()
现在您可以根据需要使用cls,而不是基类。 它可以完成基类所能做的一切,以及扩展所能做的一切:
>>> obj = cls() >>> obj.method1() 'Test' >>> obj.cool_attribute 1
可扩展的ByHashType
与 extensibletype 相同,但允许构建类树 用于不同的名称(类型)。请看下面的示例。
首先,创建指定继承规则的元类:
>>> import six # Used for Python 2/3 compatability >>> mc = ExtensibleByHashType._("Connector", hashattr='name')
这里我们看到的是方法中的附加参数: hashattr='name' 它描述了将哪些元属性用作键(散列)。
下一步-我们必须用这个元类创建基类。 例如,我们将研究 openerproxy 项目的连接类:
>>> @six.add_metaclass(mc) ... class ConnectorBase(object): ... # Base class for all connectors ... ... def __init__(self, host, port, verbose=False): ... self.host = host ... self.port = port ... self.verbose = verbose ... ... def _get_service(self, name): ... raise NotImplementedError ... ... def get_service(self, name): ... # Returns service for specified *name* ... return self._get_service(name)
基类只描述接口,可能是抽象逻辑的一部分 下一步我们将以不同的方式扩展它以支持不同的 连接类型:
>>> class ConnectorXMLRPC(ConnectorBase): ... # XML-RPC connector ... class Meta: ... name = 'xml-rpc' # remember definition of metaclass? ... # this attribute is used as hash(key) ... # to unique identify each banch of extensions ... # of base class ... ... def __init__(self, *args, **kwargs): ... super(ConnectorXMLRPC, self).__init__(*args, **kwargs) ... self.__services = {} ... ... def get_service_url(self, service_name): ... return 'http://%s:%s/xmlrpc/%s' % (self.host, self.port, service_name) ... ... def _get_service(self, name): ... service = self.__services.get(name, False) ... if service is False: ... service = XMLRPCProxy(self.get_service_url(name), verbose=self.verbose) ... self.__services[name] = service ... return service ... ... ... # Pay attention on base class. >>> class ConnectorXMLRPCS(ConnectorXMLRPC): ... # XML-RPCS Connector ... class Meta: ... name = 'xml-rpcs' ... ... def get_service_url(self, service_name): ... return 'https://%s:%s/xmlrpc/%s' % (self.host, self.port, service_name)
上面的代码创建了两个连接器:一个用于 xml-rpc ,另一个用于 xml-rpcs 。 每个连接器都可以通过简单的继承来扩展。如果需要的话 扩展可以定义新的分支(键)(散列),如上文示例所示。
要使用此连接器,mc 有方法 获取类(name[,default=false]) wich将返回为hash=*name*:
生成的类>>> cls = mc.get_class('xml-rpc') >>> [b.__name__ for b in cls.__bases__] ['ConnectorXMLRPC', 'ConnectorBase'] >>> cls.__name__ 'Connector' >>> cls = mc.get_class('xml-rpcs') >>> [b.__name__ for b in cls.__bases__] ['ConnectorXMLRPCS', 'ConnectorBase'] >>> cls.__name__ 'Connector'
上面的示例显示将为指定的名称生成哪些类。 默认情况下,如果使用未注册的名称调用mc.get_class (未定义扩展名meta.name==name)它将引发 valueerror
如果要允许创建未定义meta.name 的类, 只需将 default=true 传递到 mc。获取类: :
>>> cls = mc.get_class('unexisting-protocol', default=True) >>> [b.__name__ for b in cls.__bases__] ['ConnectorBase'] >>> cls.__name__ 'Connector'
可扩展
这个类提供了一个更高层次的抽象,允许隐藏所有的元类魔术 看在眼前。所以,使用它不需要担心元类和类 创建过程。从基类继承扩展,并在程序中使用 基类的实例。让我们在示例中看到它:
>>> import six # Used for Python 2/3 compatability >>> mc = ExtensibleType._("Object") >>> @six.add_metaclass(mc) ... class Object(object): ... pass0
现在只要使用基类的实例,就可以使用扩展提供的所有功能:
>>> import six # Used for Python 2/3 compatability >>> mc = ExtensibleType._("Object") >>> @six.add_metaclass(mc) ... class Object(object): ... pass1