Python:使用_导入时执行相对导入?

Python:使用_导入时执行相对导入?,python,import,Python,Import,以下是此测试中的文件: main.py app/ |- __init__.py |- master.py |- plugin/ |- |- __init__.py |- |- p1.py |- |_ p2.py 这个想法是要有一个插件功能的应用程序。新的.py或.pyc文件可以放入符合我的API的插件中 我在应用程序级别有一个master.py文件,其中包含所有插件可能需要访问的全局变量和函数,以及应用程序本身。出于本测试的目的,“app”由app/_init__u;.py中

以下是此测试中的文件:

main.py
app/
 |- __init__.py
 |- master.py
 |- plugin/
 |-  |- __init__.py
 |-  |- p1.py
 |-  |_ p2.py
这个想法是要有一个插件功能的应用程序。新的.py或.pyc文件可以放入符合我的API的插件中

我在应用程序级别有一个
master.py
文件,其中包含所有插件可能需要访问的全局变量和函数,以及应用程序本身。出于本测试的目的,“app”由app/_init__u;.py中的测试函数组成。实际上,应用程序可能会被移动到单独的代码文件中,但我只会在该代码文件中使用
import master
,以引入对
master
的引用

以下是文件内容:

main.py:

import app

app.test()
app.test2()
import os, os.path, sys

class MyApp:

    _plugins = []

    def __init__(self):
        self.myVar = 0

    def loadPlugins(self):
        scriptDir = os.path.join ( os.path.dirname(os.path.abspath(__file__)), "plugin" )   
        sys.path.insert(0,scriptDir)
        for plug in os.listdir(scriptDir):
            if (plug[-3:].lower() == ".py"):
                m = __import__(os.path.basename(plug)[:-3])
                self._plugins.append(m.Plugin(self))

    def runTests(self):
        for p in self._plugins:
            p.test()

if (__name__ == "__main__"):
    app = MyApp()
    app.loadPlugins()
    app.runTests()
app/\uuuu init\uuuuu.py:

import sys, os

from plugin import p1

def test():
        print "__init__ in app is executing test"
        p1.test()

def test2():
        print "__init__ in app is executing test2"
        scriptDir = os.path.join ( os.path.dirname(os.path.abspath(__file__)), "plugin" )
        print "The scriptdir is %s" % scriptDir
        sys.path.insert(0,scriptDir)
        m = __import__("p2", globals(), locals(), [], -1)
        m.test()
<empty file>
app/master.py:

myVar = 0
app/plugin/\uuuuu init\uuuuuu.py:

import sys, os

from plugin import p1

def test():
        print "__init__ in app is executing test"
        p1.test()

def test2():
        print "__init__ in app is executing test2"
        scriptDir = os.path.join ( os.path.dirname(os.path.abspath(__file__)), "plugin" )
        print "The scriptdir is %s" % scriptDir
        sys.path.insert(0,scriptDir)
        m = __import__("p2", globals(), locals(), [], -1)
        m.test()
<empty file>
app/plugin/p2.py:

from .. import master

def test():
    master.myVar = 2
    print "test in p2 is running"
    print "from p2, myVar: %d" % master.myVar
class Plugin:

    def __init__(self, host):
        self.host = host

    def test(self):
        print "from p2: variable set"
        self.host.myVar = 1
        print "from p2: myVar = %d" % self.host.myVar
因为我显式地导入了
p1
模块,所以一切都按预期工作。但是,当我使用
\uuuuu import\uuuuu
导入p2时,会出现以下错误:

__init__ in app is executing test
test in p1 is running
from p1: myVar = 0
__init__ in app is executing test2
The scriptdir is ....../python/test1/app/plugin
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    app.test2()
  File "....../python/test1/app/__init__.py", line 17, in test2
    m = __import__("p2", globals(), locals(), [], -1)
  File "....../python/test1/app/plugin/p2.py", line 1, in <module>
    from .. import master
ValueError: Attempted relative import in non-package
(返回与上面相同的精确错误)

(返回对app.plugin的引用,而不是对app.plugin.p2的引用)

(返回对app.plugin的引用,而不是对app.plugin.p2的引用)

(返回:)

回溯(最近一次呼叫最后一次):
文件“main.py”,第4行,在
app.test2()
文件“…/python/test1/app/_init__uuu.py”,第20行,在test2中
m=importlib.import\u模块(“plugin.p2”)
文件“/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/_init__.py”,第37行,在导入模块中
__导入(名称)
ImportError:没有名为plugin.p2的模块

我也遇到过类似的问题。
\uuuuu import\uuuuu
仅在所有父
\uuuu init\uuuuuuu.py
文件为空时导入子模块。 您应该改用importlib

import importlib

p2 = importlib.import_module('plugin.p2')

我从来没有找到解决方案,所以我最终决定重组这个项目

我所做的是将主应用程序设置为一个类。然后,我还将每个插件更改为一个类。然后,当我使用导入加载插件时,我还实例化了每个插件中具有预定义名称的类,并将引用传递给主应用程序类

这意味着每个类都可以通过使用引用直接读取和操作宿主类中的变量。它是完全灵活的,因为宿主类导出的任何内容都可以被所有插件访问

事实证明,这种方法更有效,而且不依赖于相对路径和其他任何东西。这也意味着理论上一个Python解释器可以同时运行主机应用程序的多个实例(例如,在不同的线程上),插件仍然会引用正确的主机实例

我基本上是这样做的:

main.py:

import app

app.test()
app.test2()
import os, os.path, sys

class MyApp:

    _plugins = []

    def __init__(self):
        self.myVar = 0

    def loadPlugins(self):
        scriptDir = os.path.join ( os.path.dirname(os.path.abspath(__file__)), "plugin" )   
        sys.path.insert(0,scriptDir)
        for plug in os.listdir(scriptDir):
            if (plug[-3:].lower() == ".py"):
                m = __import__(os.path.basename(plug)[:-3])
                self._plugins.append(m.Plugin(self))

    def runTests(self):
        for p in self._plugins:
            p.test()

if (__name__ == "__main__"):
    app = MyApp()
    app.loadPlugins()
    app.runTests()
plugin/p1.py:

from .. import master

def test():
    print "test in p1 is running"
    print "from p1: myVar = %d" % master.myVar
class Plugin:

    def __init__(self, host):
        self.host = host

    def test(self):
        print "from p1: myVar = %d" % self.host.myVar
plugin/p2.py:

from .. import master

def test():
    master.myVar = 2
    print "test in p2 is running"
    print "from p2, myVar: %d" % master.myVar
class Plugin:

    def __init__(self, host):
        self.host = host

    def test(self):
        print "from p2: variable set"
        self.host.myVar = 1
        print "from p2: myVar = %d" % self.host.myVar

这方面还有一些改进的余地,例如,验证每个导入的.py文件,看看它是否实际上是一个插件,等等。但这与预期的一样有效。

您是否尝试过以下语法:


我也遇到了类似的问题……

可能是重复的。或者,你可以像我在回答这个问题时建议的那样做……基本上是在app/master/plugin中获取一个文件列表,并动态加载它们:@blazetopher你是说取消master.py,而只是使用全局名称空间吗?不知何故,这充其量似乎有点危险-可能的名称冲突等等…?您可以在master中进行动态导入,但对名称空间冲突的担忧是真实的。也就是说,任何时候允许动态导入时,都可能发生此类冲突(即,如果p1和p2都有“测试”方法)。我想这取决于你的程序的使用环境,你能灌输一些惯例来限制这种可能性吗?您还可以考虑将插件架构类(继承)作为基础,这将有助于减少RISKI能够尽最大努力保护冲突。问题仍然是插件中的代码本身需要访问master.py文件中的内容。py将包含所有插件可能需要访问的函数或变量。因此,我仍然需要能够从插件导入master来访问它,这又导致了最初的问题,即如果我使用
\uuuuu import\uuuu
则使用
from..
会失败,但如果我使用模块级import语句显式导入,则会起作用…抱歉,不起作用。。。见上文。我没有说清楚,但我使用的是Python 2,所以也许这就是为什么。。。我认为importlib主要是Python3的东西?你可以在2.7中使用它