把不同的python包放在同一个命名空间中?

2024-05-23 19:46:17 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在开发一个python框架,它将“插件”作为单独的包编写。一、 e.:

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.py

fooext/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/安装位置,但这样会使开发和部署的名称空间有所不同。

有没有更好的方法来实现这一点,或者也许有一个不同的方法来解决上述分配问题?


Tags: path方法代码pyimport插件框架foo
3条回答

Setuptools能够按名称查找包“入口点”(函数、对象等)。Trac使用这个机制来load its plugins,它工作得很好。

Is there a better way to accomplish this or perhaps a different approach to the above distribution problem altogether?

可能吧。Python的模块/包设置通常很难像这样进行动态修改,但是它的对象/类系统是开放的,并且可以以定义良好的方式进行扩展。当模块和包没有很好地封装项目所需的特性时,可以使用类来代替。

例如,您可以在完全不同的包中拥有扩展功能,但允许它通过特定的接口将类注入到基本框架中。例如,myframework/uuuuuuinit.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中使用扩展功能,该功能保留对其“owner”或“outer”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”,你只能得到基本的功能。但是如果你同时“import myexts.helloer”,你也可以调用MyFramework.helloer.hello()。当然,您也可以为插件定义协议,以便与基本框架行为以及彼此进行交互。您还可以执行内部类之类的操作如果您需要这种复杂程度,框架的子类可以重写以自定义,而不必修复可能影响其他应用程序的类。

这样的封装行为可能很有用,但是调整模块级代码通常是很烦人的工作,您必须适应这个模型。

相关问题 更多 >