将单独的python包放入相同的命名空间?

Dim*_*iuc 15 python namespaces distribution extend

我正在开发一个python框架,它将"插件"写成单独的包.即:

import myframework
from myframework.addons import foo, bar
Run Code Online (Sandbox Code Playgroud)

现在,我正在尝试安排的是这些插件可以与核心框架分开分发并注入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
Run Code Online (Sandbox Code Playgroud)

fooext/myframework/addons/__init__.py将有pkgutil路径扩展代码:

import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
Run Code Online (Sandbox Code Playgroud)

问题是,为了使这个工作,PYTHONPATH需要有fooext/它,但它唯一的东西是父安装目录(很可能是上面提到的site-packages).

这个问题的解决是有额外的代码,myframework/addons/__init__.py这将tranverse sys.path,寻找与myframework子包,在这种情况下将其添加到任何模块sys.path和一切正常.

我的另一个想法是直接编写addon文件来myframework/addons/安装位置,但是它会使开发和部署的命名空间不同.

是否有更好的方法来实现这一点,或者可能采用不同的方法解决上述分配问题?

Ale*_*mas 5

setuptools 能够按名称查找包“入口点”(函数、对象等)。Trac 使用这种机制来加载其插件,并且效果良好。


bob*_*nce 4

\n

是否有更好的方法来完成此任务,或者可能采用不同的方法来解决上述分配问题?

\n
\n\n

可能吧。Python 的模块/包设置通常很难像这样动态篡改,但它的对象/类系统是开放的并且可以以明确定义的方式扩展。当模块和包不具备很好地封装项目所需的功能时,您可以使用类来代替。

\n\n

例如,您可以在完全不同的包中拥有扩展功能,但允许它通过特定接口将类注入到您的基本框架中。例如。myframework/_\xe2\x80\x8b\xe2\x80\x8b_\xe2\x80\x8binit\xe2\x80\x8b_\xe2\x80\x8b\xe2\x80\x8b_.py 包含基本应用程序包装器:

\n\n
class MyFramework(object):\n    """A bare MyFramework, I only hold a person\'s name\n    """\n    _addons= {}\n    @staticmethod\n    def addAddon(name, addon):\n        MyFramework._addons[name]= addon\n\n    def __init__(self, person):\n        self.person= person\n        for name, addon in MyFramework._addons.items():\n            setattr(self, name, addon(self))\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,您可以在 myexts/helloer.py 中拥有扩展功能,该功能保留对其“所有者”或“外部”MyFramework 类实例的引用:

\n\n
class Helloer(object):\n    def __init__(self, owner):\n        self.owner= owner\n    def hello(self):\n        print \'hello \'+self.owner.person\n\nimport myframework\nmyframework.MyFramework.addAddon(\'helloer\', Helloer)\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,现在如果您只是“导入 myframework”,您只能获得基本功能。但如果您还“导入 myexts.helloer”,您还可以调用 MyFramework.helloer.hello()。当然,您还可以为插件定义协议以与基本框架行为以及彼此之间进行交互。如果您需要这种级别的复杂性,您还可以执行诸如框架的子类可以重写的内部类之类的操作来进行自定义,而无需对可能影响其他应用程序的类进行猴子修补。

\n\n

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

\n