以下是此测试中的文件:
main.py
app/
|- __init__.py
|- master.py
|- plugin/
|- |- __init__.py
|- |- p1.py
|- |_ p2.py
我们的想法是拥有一个支持插件的应用。新的.py或.pyc文件可以放入与我的API相关的插件中。
我在应用程序级别有一个master.py
文件,其中包含任何和所有插件可能需要访问的全局变量和函数,以及应用程序本身。出于此测试的目的,“app”由app / __ init__.py中的测试函数组成。在实践中,应用程序可能会被移动到单独的代码文件中,但之后我会在该代码文件中使用import master
来引用master
。
这是文件内容:
main.py:
import app
app.test()
app.test2()
应用程序/ __ INIT __ 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()
应用程序/ master.py:
myVar = 0
应用程序/插件/ __初始化__ PY:
<empty file>
应用程序/插件/ p1.py:
from .. import master
def test():
print "test in p1 is running"
print "from p1: myVar = %d" % master.myVar
应用程序/插件/ p2.py:
from .. import master
def test():
master.myVar = 2
print "test in p2 is running"
print "from p2, myVar: %d" % master.myVar
由于我明确导入了p1
模块,所以一切都按预期工作。但是,当我使用__import__
导入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
执行继续执行test()函数并且错误输出正确,因为test2()尝试执行其__import__
语句,而p2又尝试执行相对导入(执行< / strong>在通过import语句显式导入p1时工作,回忆)
很明显,使用__import__
做的事情与使用import
语句不同。 Python文档声明使用import只是在内部转换为__import__
语句,但必须有更多的进展,而不是满足于眼睛。
由于应用程序是基于插件的,因此在主应用程序中编写显式导入语句当然不可行。在
中使用导入本身我在这里缺少什么?当使用__import__
手动导入模块时,如何让Python按预期运行?似乎我可能没有完全理解相对导入的想法,或者我只是遗漏了导入发生的位置(即在函数内部而不是在代码文件的根部)
m = __import__("p2",globals(),locals(),"plugin")
(返回与上面完全相同的错误)
m = __import__("plugin",fromlist="p2")
(返回对app.plugin的引用,而不是对app.plugin.p2的引用)
m = __import__("plugin.p2",globals(),locals())
(返回对app.plugin的引用,而不是对app.plugin.p2的引用)
import importlib
m = importlib.import_module("plugin.p2")
(返回:)
Traceback (most recent call last):
File "main.py", line 4, in <module>
app.test2()
File "....../python/test1/app/__init__.py", line 20, in test2
m = importlib.import_module("plugin.p2")
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
ImportError: No module named plugin.p2
答案 0 :(得分:3)
我遇到了类似的问题
如果所有父__import__
个文件都为空,__init__.py
仅导入子模块。
您应该使用importlib
import importlib
p2 = importlib.import_module('plugin.p2')
答案 1 :(得分:1)
我从来没有找到解决方案,所以我最终决定重组该计划。
我所做的是将主应用程序设置为一个类。然后,我还将每个插件更改为一个类。然后,当我使用 import 加载插件时,我还在每个插件中实例化具有预定义名称的类,并将引用传递给主app类。
这意味着每个类只需使用引用即可直接在宿主类中读取和操作变量。它非常灵活,因为主机类导出的任何可由所有插件访问。
事实证明这更有效,并且不依赖于相对路径和任何这些东西。这也意味着一个Python解释器理论上可以同时运行 host 应用程序的多个实例(例如,在不同的线程上),并且插件仍将引用回正确的主机实例。
这基本上就是我所做的:
main.py:
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()
插件/ p1.py:
class Plugin:
def __init__(self, host):
self.host = host
def test(self):
print "from p1: myVar = %d" % self.host.myVar
插件/ p2.py:
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文件,看看它是否真的是一个插件,依此类推。但这可以按预期工作。
答案 2 :(得分:1)