我正在开发一个python框架,它将把“插件”写成单独的包。即:
import myframework
from myframework.addons import foo, bar现在,我试图安排的是,这些插件可以独立于核心框架分发,并注入到myframework.addons命名空间中。
目前,我对此的最佳解决方案如下。将部署一个附加组件(最有可能部署到{python_version}/site-packages/中,如下所示:
fooext/
fooext/__init__.py
fooext/myframework/
fooext/myframework/__init__.py
fooext/myframework/addons/
fooext/myframework/addons/__init__.py
fooext/myframework/addons/foo.pyfooext/myframework/addons/__init__.py将具有pkgutil路径扩展代码:
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)问题是,为了让它工作,PYTHONPATH中需要有fooext/,但是它唯一需要的是父安装目录(最有可能是上面提到的site-packages)。
这个问题的解决方案是在myframework/addons/__init__.py中有额外的代码,它将遍历sys.path并查找任何带有MyFramework子程序包的模块,在这种情况下,它会将其添加到sys.path中,一切都会正常工作。
我的另一个想法是将插件文件直接写入myframework/addons/安装位置,但这样做会使开发和部署的命名空间不同。
有没有更好的方法来实现这一点,或者也许有一种完全不同的方法来解决上面的分布问题?
发布于 2009-01-18 15:01:31
有没有更好的方法来实现这一点,或者可能有一种完全不同的方法来解决上面的分发问题?
有可能。Python的模块/包设置通常很难像这样动态地进行篡改,但是它的对象/类系统是开放的,并且可以以定义良好的方式进行扩展。当模块和包没有很好地封装项目所需的功能时,您可以使用类来代替。
例如,您可以将扩展功能放在一个完全不同的包中,但允许它通过特定接口将类注入到您的基本框架中。例如:包含基本应用程序包装器的myframework/__init__.py:
class MyFramework(object):
    """A bare MyFramework, I only hold a person's name
    """
    _addons= {}
    @staticmethod
    def addAddon(name, addon):
        MyFramework._addons[name]= addon
    def __init__(self, person):
        self.person= person
        for name, addon in MyFramework._addons.items():
            setattr(self, name, addon(self))然后,您可以在myexts/helloer.py中拥有扩展功能,它保留对其“所有者”或“外部”MyFramework类实例的引用:
class Helloer(object):
    def __init__(self, owner):
        self.owner= owner
    def hello(self):
        print 'hello '+self.owner.person
import myframework
myframework.MyFramework.addAddon('helloer', Helloer)所以现在如果你只是“导入myframework",你只能得到基本的功能。但是,如果您还“导入myexts.helloer”,您还可以调用MyFramework.helloer.hello()。当然,您也可以为插件定义协议,以与基本框架行为进行交互,并相互进行交互。如果你需要这样的复杂性,你也可以做一些事情,比如框架的子类可以覆盖内部类来进行定制,而不必修补可能会影响其他应用程序的类。
封装这样的行为可能很有用,但为了适应这个模型,调整模块级代码通常是一项烦人的工作。
https://stackoverflow.com/questions/454691
复制相似问题